From 33541d5e55c3114e01e06b27715ae04372ce027f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Apr 2020 14:45:37 +0200 Subject: [PATCH 001/695] clarify interaction of pin drop guarantee and panics --- src/libcore/pin.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 774ecd997c201..6f5bf7ad9da52 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -139,10 +139,12 @@ //! otherwise invalidating the memory used to store the data is restricted, too. //! Concretely, for pinned data you have to maintain the invariant //! that *its memory will not get invalidated or repurposed from the moment it gets pinned until -//! when [`drop`] is called*. Memory can be invalidated by deallocation, but also by +//! when [`drop`] is called*. Only once [`drop`] returns or panics, the memory may be reused. +//! +//! Memory can be "invalidated" by deallocation, but also by //! replacing a [`Some(v)`] by [`None`], or calling [`Vec::set_len`] to "kill" some elements //! off of a vector. It can be repurposed by using [`ptr::write`] to overwrite it without -//! calling the destructor first. +//! calling the destructor first. None of this is allowed for pinned data without calling [`drop`]. //! //! This is exactly the kind of guarantee that the intrusive linked list from the previous //! section needs to function correctly. From ef485c6fa97a562b0bc559ffbe38fee9bf1f745b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Tue, 7 Apr 2020 14:51:47 +0200 Subject: [PATCH 002/695] Impl Error for Infallible --- src/libstd/error.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 24b57f12e8df4..3b4cb859dd425 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -14,6 +14,7 @@ // reconsider what crate these items belong in. use core::array; +use core::convert::Infallible; use crate::alloc::{AllocErr, LayoutErr}; use crate::any::TypeId; @@ -474,7 +475,7 @@ impl Error for string::FromUtf16Error { } #[stable(feature = "str_parse_error2", since = "1.8.0")] -impl Error for string::ParseError { +impl Error for Infallible { fn description(&self) -> &str { match *self {} } From 58ae4a9a5388d9c2c5e4ac435ea69a2b456ab008 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 12:13:27 +0200 Subject: [PATCH 003/695] de-promote Duration::from_secs --- src/libcore/time.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/time.rs b/src/libcore/time.rs index ed1d5d46db5c4..e2ceaf80c0cda 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -152,7 +152,6 @@ impl Duration { /// ``` #[stable(feature = "duration", since = "1.3.0")] #[inline] - #[rustc_promotable] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] pub const fn from_secs(secs: u64) -> Duration { Duration { secs, nanos: 0 } From dfbc143e65dd4dc8499f7296ddc7889854a8cc7d Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Sun, 3 May 2020 11:00:25 +0200 Subject: [PATCH 004/695] Adding if to prevent borrowing suggestion in structs #71136 --- .../traits/error_reporting/suggestions.rs | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 5ec2d68ab2a7d..37f567401b74a 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -562,6 +562,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { param_env, new_trait_ref.without_const().to_predicate(), ); + if self.predicate_must_hold_modulo_regions(&new_obligation) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument @@ -569,6 +570,34 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // original type obligation, not the last one that failed, which is arbitrary. // Because of this, we modify the error to refer to the original obligation and // return early in the caller. + + + let has_colon = self + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map(|w| w.contains(":")) + .unwrap_or(false); + + let has_double_colon = self + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map(|w| w.contains("::")) + .unwrap_or(false); + + let has_bracket = self + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map(|w| w.contains("{")) + .unwrap_or(false); + + + let msg = format!( "the trait bound `{}: {}` is not satisfied", found, @@ -591,12 +620,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.parent_trait_ref.skip_binder().print_only_trait_path(), ), ); - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::MaybeIncorrect, - ); + + // This if is to prevent a special edge-case + if !has_colon || has_double_colon || has_bracket { + // We don't want a borrowing suggestion on the fields in structs, + // ``` + // struct Foo { + // the_foos: Vec + // } + // ``` + + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::MaybeIncorrect, + ); + } return true; } } From bc29f1d062feeb68207c961d254652d6bff9fd9b Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Sun, 3 May 2020 11:11:23 +0200 Subject: [PATCH 005/695] Adding new test #71136 --- src/test/ui/traits/traits-issue-71136.rs | 8 ++++++++ src/test/ui/traits/traits-issue-71136.stderr | 13 +++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/ui/traits/traits-issue-71136.rs create mode 100644 src/test/ui/traits/traits-issue-71136.stderr diff --git a/src/test/ui/traits/traits-issue-71136.rs b/src/test/ui/traits/traits-issue-71136.rs new file mode 100644 index 0000000000000..b21756e2b637f --- /dev/null +++ b/src/test/ui/traits/traits-issue-71136.rs @@ -0,0 +1,8 @@ +struct Foo(u8); + +#[derive(Clone)] +struct FooHolster { + the_foos: Vec, //~ERROR Clone +} + +fn main() {} diff --git a/src/test/ui/traits/traits-issue-71136.stderr b/src/test/ui/traits/traits-issue-71136.stderr new file mode 100644 index 0000000000000..4c0a43062f60d --- /dev/null +++ b/src/test/ui/traits/traits-issue-71136.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `Foo: std::clone::Clone` is not satisfied + --> $DIR/traits-issue-71136.rs:5:5 + | +LL | the_foos: Vec, + | ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `std::clone::Clone` + | + = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` + = note: required by `std::clone::Clone::clone` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From d232be80f82b052fd023eb2f4904ccad0aa42d7a Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Sun, 3 May 2020 13:56:46 +0200 Subject: [PATCH 006/695] Fix tidy checks --- .../traits/error_reporting/suggestions.rs | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 37f567401b74a..c90769c66556d 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -570,33 +570,30 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // original type obligation, not the last one that failed, which is arbitrary. // Because of this, we modify the error to refer to the original obligation and // return early in the caller. - let has_colon = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|w| w.contains(":")) - .unwrap_or(false); + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map(|w| w.contains(":")) + .unwrap_or(false); let has_double_colon = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|w| w.contains("::")) - .unwrap_or(false); + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map(|w| w.contains("::")) + .unwrap_or(false); let has_bracket = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|w| w.contains("{")) - .unwrap_or(false); - - + .tcx + .sess + .source_map() + .span_to_snippet(span) + .map(|w| w.contains("{")) + .unwrap_or(false); let msg = format!( "the trait bound `{}: {}` is not satisfied", @@ -620,7 +617,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.parent_trait_ref.skip_binder().print_only_trait_path(), ), ); - + // This if is to prevent a special edge-case if !has_colon || has_double_colon || has_bracket { // We don't want a borrowing suggestion on the fields in structs, From 17d877cce28b22b9b345ec7ef8b14859d8b165c4 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 3 May 2020 15:59:57 +0200 Subject: [PATCH 007/695] Update contributing section about syncing Clippy --- CONTRIBUTING.md | 72 +++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50a5ee8bbf3c8..079a51eae3ba1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -155,47 +155,37 @@ That's why the `else_if_without_else` example uses the `register_early_pass` fun ## Fixing build failures caused by Rust -Clippy will sometimes fail to build from source because building it depends on unstable internal Rust features. Most of -the times we have to adapt to the changes and only very rarely there's an actual bug in Rust. Fixing build failures -caused by Rust updates, can be a good way to learn about Rust internals. - -In order to find out why Clippy does not work properly with a new Rust commit, you can use the [rust-toolstate commit -history][toolstate_commit_history]. You will then have to look for the last commit that contains -`test-pass -> build-fail` or `test-pass -> test-fail` for the `clippy-driver` component. -[Here][toolstate_commit] is an example. - -The commit message contains a link to the PR. The PRs are usually small enough to discover the breaking API change and -if they are bigger, they likely include some discussion that may help you to fix Clippy. - -To check if Clippy is available for a specific target platform, you can check -the [rustup component history][rustup_component_history]. - -If you decide to make Clippy work again with a Rust commit that breaks it, -you probably want to install the latest Rust from master locally and run Clippy -using that version of Rust. - -You can set up the master toolchain by running `./setup-toolchain.sh`. That script will install -[rustup-toolchain-install-master][rtim] and master toolchain, then run `rustup override set master`. - -After fixing the build failure on this repository, we can submit a pull request -to [`rust-lang/rust`] to fix the toolstate. - -To submit a pull request, you should follow these steps: - -```bash -# Assuming you already cloned the rust-lang/rust repo and you're in the correct directory -git submodule update --remote src/tools/clippy -cargo update -p clippy -git add -u -git commit -m "Update Clippy" -./x.py test -i --stage 1 src/tools/clippy # This is optional and should succeed anyway -# Open a PR in rust-lang/rust -``` - -[rustup_component_history]: https://rust-lang.github.io/rustup-components-history -[toolstate_commit_history]: https://github.com/rust-lang-nursery/rust-toolstate/commits/master -[toolstate_commit]: https://github.com/rust-lang-nursery/rust-toolstate/commit/aad74d8294e198a7cf8ac81a91aebb7f3bbcf727 -[rtim]: https://github.com/kennytm/rustup-toolchain-install-master +Clippy currently gets build with `rustc` of the `rust-lang/rust` `master` +branch. Most of the times we have to adapt to the changes and only very rarely +there's an actual bug in Rust. + +If you decide to make Clippy work again with a Rust commit that breaks it, you +have to sync the `rust-lang/rust-clippy` repository with the `subtree` copy of +Clippy in the `rust-lang/rust` repository. + +For general information about `subtree`s in the Rust repository see [Rust's +`CONTRIBUTING.md`][subtree]. + +Here is a TL;DR version of the sync process: + +1. Clone the [`rust-lang/rust`] repository (all of the following commands have + to be run inside the `rust` directory) +2. Sync the changes to the copy of Clippy to your fork of the Clippy repository: + ```bash + # Make sure to change `your-github-name` to your github name in the following command + git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust + ``` +3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to + accelerate the process ping the `@rust-lang/clippy` team in your PR and/or + ~~annoy~~ ask them in the [Discord] channel.) +4. Sync the `rust-lang/rust-clippy` master to the copy of Clippy: + ```bash + git checkout -b sync-from-clippy + git subtree pull -P src/tools/clippy https://github.com/rust-lang/rust-clippy master + ``` +5. Open a PR to [`rust-lang/rust`] + +[subtree]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust ## Issue and PR triage From 2ce3f85d46edbf5105f2e93d2cbe56ad777b41e6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 3 May 2020 06:23:15 -0700 Subject: [PATCH 008/695] Tweak and stabilize AtomicN::fetch_update --- src/libcore/sync/atomic.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 220f221cdd36d..f9d31f0a7d793 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1809,11 +1809,10 @@ Note: This may call the function multiple times if the value has been changed fr the meantime, as long as the function returns `Some(_)`, but the function will have been applied but once to the stored value. -`fetch_update` takes two [`Ordering`] arguments to describe the memory -ordering of this operation. The first describes the required ordering for loads -and failed updates while the second describes the required ordering when the -operation finally succeeds. Beware that this is different from the two -modes in [`compare_exchange`]! +`fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. +The first describes the required ordering for when the operation finally succeeds while the second +describes the required ordering for loads. These correspond to the success and failure orderings of +[`compare_exchange`] respectively. Using [`Acquire`] as success ordering makes the store part of this operation [`Relaxed`], and using [`Release`] makes the final successful load @@ -1831,24 +1830,21 @@ and must be equivalent to or weaker than the success ordering. # Examples ```rust -#![feature(no_more_cas)] ", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; let x = ", stringify!($atomic_type), "::new(7); -assert_eq!(x.fetch_update(|_| None, Ordering::SeqCst, Ordering::SeqCst), Err(7)); -assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(7)); -assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(8)); +assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7)); +assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7)); +assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8)); assert_eq!(x.load(Ordering::SeqCst), 9); ```"), #[inline] - #[unstable(feature = "no_more_cas", - reason = "no more CAS loops in user code", - issue = "48655")] + #[stable(feature = "no_more_cas", since = "1.45.0")] #[$cfg_cas] pub fn fetch_update(&self, - mut f: F, + set_order: Ordering, fetch_order: Ordering, - set_order: Ordering) -> Result<$int_type, $int_type> + mut f: F) -> Result<$int_type, $int_type> where F: FnMut($int_type) -> Option<$int_type> { let mut prev = self.load(fetch_order); while let Some(next) = f(prev) { From c1698fedeb69109f9b1aebc0bfccd9bf3112ccad Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 3 May 2020 16:47:57 +0200 Subject: [PATCH 009/695] Apply suggestions from code review Co-authored-by: Phil Hansch --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 079a51eae3ba1..f7a6093837440 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -155,7 +155,7 @@ That's why the `else_if_without_else` example uses the `register_early_pass` fun ## Fixing build failures caused by Rust -Clippy currently gets build with `rustc` of the `rust-lang/rust` `master` +Clippy currently gets built with `rustc` of the `rust-lang/rust` `master` branch. Most of the times we have to adapt to the changes and only very rarely there's an actual bug in Rust. @@ -170,7 +170,7 @@ Here is a TL;DR version of the sync process: 1. Clone the [`rust-lang/rust`] repository (all of the following commands have to be run inside the `rust` directory) -2. Sync the changes to the copy of Clippy to your fork of the Clippy repository: +2. Sync the changes to the rust-copy of Clippy to your Clippy fork: ```bash # Make sure to change `your-github-name` to your github name in the following command git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust @@ -178,7 +178,7 @@ Here is a TL;DR version of the sync process: 3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to accelerate the process ping the `@rust-lang/clippy` team in your PR and/or ~~annoy~~ ask them in the [Discord] channel.) -4. Sync the `rust-lang/rust-clippy` master to the copy of Clippy: +4. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy: ```bash git checkout -b sync-from-clippy git subtree pull -P src/tools/clippy https://github.com/rust-lang/rust-clippy master From 2d10babb71f6658c39279425ec5cda11a28d3af4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 1 Feb 2020 01:02:31 +0300 Subject: [PATCH 010/695] Stabilize fn-like proc macros in expression, pattern and statement positions --- mini-macro/src/lib.rs | 2 +- tests/ui/auxiliary/proc_macro_derive.rs | 2 +- tests/ui/crashes/ice-3741.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mini-macro/src/lib.rs b/mini-macro/src/lib.rs index 92b6f70155577..ba946563ec595 100644 --- a/mini-macro/src/lib.rs +++ b/mini-macro/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(proc_macro_quote, proc_macro_hygiene)] +#![feature(proc_macro_quote)] #![deny(rust_2018_idioms)] // FIXME: Remove this attribute once the weird failure is gone. #![allow(unused_extern_crates)] diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 21bb5b01e02b5..05ffb55f6207e 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -1,7 +1,7 @@ // no-prefer-dynamic #![crate_type = "proc-macro"] -#![feature(repr128, proc_macro_hygiene, proc_macro_quote)] +#![feature(repr128, proc_macro_quote)] extern crate proc_macro; diff --git a/tests/ui/crashes/ice-3741.rs b/tests/ui/crashes/ice-3741.rs index 74b9c9c86c81c..a548415da62bd 100644 --- a/tests/ui/crashes/ice-3741.rs +++ b/tests/ui/crashes/ice-3741.rs @@ -1,7 +1,6 @@ // aux-build:proc_macro_crash.rs // run-pass -#![feature(proc_macro_hygiene)] #![warn(clippy::suspicious_else_formatting)] extern crate proc_macro_crash; From 31c820552350e3f686a6f353982f0f31ecbaf4a7 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 3 May 2020 19:36:12 -0400 Subject: [PATCH 011/695] Update src/libcore/sync/atomic.rs Co-authored-by: Ralf Jung --- src/libcore/sync/atomic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index f9d31f0a7d793..0e0ebfa1a452f 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1807,7 +1807,7 @@ new value. Returns a `Result` of `Ok(previous_value)` if the function returned ` Note: This may call the function multiple times if the value has been changed from other threads in the meantime, as long as the function returns `Some(_)`, but the function will have been applied -but once to the stored value. +only once to the stored value. `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. The first describes the required ordering for when the operation finally succeeds while the second From 1d8489c150df7d0e751f7c438541036df1a9ac5e Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Thu, 7 May 2020 23:27:21 +0200 Subject: [PATCH 012/695] perf: Revert accidental inclusion of a part of #69218 This was accidentally included in #69494 after a rebase and given how much `inflate` and `keccak` stresses the obligation forest seems like a likely culprit to the regression in those benchmarks. (It is necessary in #69218 as obligation forest needs to accurately track the root variables or unifications will get lost) --- src/librustc_trait_selection/traits/fulfill.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 1e056c96acd38..bff1fa3312980 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -240,15 +240,9 @@ struct FulfillProcessor<'a, 'b, 'tcx> { register_region_obligations: bool, } -fn mk_pending( - infcx: &InferCtxt<'_, 'tcx>, - os: Vec>, -) -> Vec> { +fn mk_pending(os: Vec>) -> Vec> { os.into_iter() - .map(|mut o| { - o.predicate = infcx.resolve_vars_if_possible(&o.predicate); - PendingPredicateObligation { obligation: o, stalled_on: vec![] } - }) + .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }) .collect() } @@ -342,7 +336,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { "selecting trait `{:?}` at depth {} yielded Ok(Some)", data, obligation.recursion_depth ); - ProcessResult::Changed(mk_pending(infcx, vtable.nested_obligations())) + ProcessResult::Changed(mk_pending(vtable.nested_obligations())) } Ok(None) => { debug!( @@ -436,7 +430,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx)); ProcessResult::Unchanged } - Ok(Some(os)) => ProcessResult::Changed(mk_pending(infcx, os)), + Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)), Err(e) => ProcessResult::Error(CodeProjectionError(e)), } } @@ -475,7 +469,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()]; ProcessResult::Unchanged } - Some(os) => ProcessResult::Changed(mk_pending(infcx, os)), + Some(os) => ProcessResult::Changed(mk_pending(os)), } } @@ -493,7 +487,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { ]; ProcessResult::Unchanged } - Some(Ok(ok)) => ProcessResult::Changed(mk_pending(infcx, ok.obligations)), + Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), Some(Err(err)) => { let expected_found = ExpectedFound::new( subtype.skip_binder().a_is_expected, From 7e855b59151f2e5c2a58fe422a273e997df14b24 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 May 2020 23:36:22 +0200 Subject: [PATCH 013/695] Clean up rustdoc source code --- src/librustdoc/docfs.rs | 5 ++++- src/librustdoc/html/render.rs | 17 ++++++++------- src/librustdoc/lib.rs | 8 ++++++- src/librustdoc/markdown.rs | 39 +++++++++++------------------------ 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs index 7ebb200abfe81..9a11e8fce28b7 100644 --- a/src/librustdoc/docfs.rs +++ b/src/librustdoc/docfs.rs @@ -12,6 +12,7 @@ use std::fs; use std::io; use std::path::Path; +use std::string::ToString; use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::Arc; @@ -25,7 +26,9 @@ macro_rules! try_err { } pub trait PathError { - fn new>(e: io::Error, path: P) -> Self; + fn new>(e: S, path: P) -> Self + where + S: ToString + Sized; } pub struct ErrorStorage { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 666e59b9a045e..c88db8c5ed00b 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -31,7 +31,6 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, VecDeque}; use std::default::Default; use std::error; - use std::ffi::OsStr; use std::fmt::{self, Formatter, Write}; use std::fs::{self, File}; @@ -40,6 +39,7 @@ use std::io::{self, BufReader}; use std::path::{Component, Path, PathBuf}; use std::rc::Rc; use std::str; +use std::string::ToString; use std::sync::Arc; use rustc_ast_pretty::pprust; @@ -92,7 +92,7 @@ crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { #[derive(Debug)] pub struct Error { pub file: PathBuf, - pub error: io::Error, + pub error: String, } impl error::Error for Error {} @@ -109,8 +109,11 @@ impl std::fmt::Display for Error { } impl PathError for Error { - fn new>(e: io::Error, path: P) -> Error { - Error { file: path.as_ref().to_path_buf(), error: e } + fn new>(e: S, path: P) -> Error + where + S: ToString + Sized, + { + Error { file: path.as_ref().to_path_buf(), error: e.to_string() } } } @@ -557,7 +560,7 @@ pub fn run( // Write shared runs within a flock; disable thread dispatching of IO temporarily. Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); - write_shared(&cx, &krate, index, &md_opts, diag)?; + write_shared(&cx, &krate, index, &md_opts)?; Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false); // And finally render the whole crate's documentation @@ -577,7 +580,6 @@ fn write_shared( krate: &clean::Crate, search_index: String, options: &RenderOptions, - diag: &rustc_errors::Handler, ) -> Result<(), Error> { // Write out the shared files. Note that these are shared among all rustdoc // docs placed in the output directory, so this needs to be a synchronized @@ -960,7 +962,8 @@ themePicker.onblur = handleThemeButtonsBlur; md_opts.output = cx.dst.clone(); md_opts.external_html = (*cx.shared).layout.external_html.clone(); - crate::markdown::render(index_page, md_opts, diag, cx.shared.edition); + crate::markdown::render(&index_page, md_opts, cx.shared.edition) + .map_err(|e| Error::new(e, &index_page))?; } else { let dst = cx.dst.join("index.html"); let page = layout::Page { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5fb7b7bf959cf..8e5dfbeeda5f4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -457,7 +457,13 @@ fn main_options(options: config::Options) -> i32 { (true, true) => return markdown::test(options, &diag), (true, false) => return test::run(options), (false, true) => { - return markdown::render(options.input, options.render_options, &diag, options.edition); + match markdown::render(&options.input, options.render_options, options.edition) { + Ok(()) => return 0, + Err(err) => { + diag.struct_err(&err).emit(); + return 1; + } + } } (false, false) => {} } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index b4c0f0ac4c5d9..1977d3653ba23 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -1,6 +1,6 @@ -use std::fs::{create_dir_all, File}; +use std::fs::{create_dir_all, read_to_string, File}; use std::io::prelude::*; -use std::path::PathBuf; +use std::path::Path; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; @@ -34,17 +34,16 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { /// Render `input` (e.g., "foo.md") into an HTML file in `output` /// (e.g., output = "bar" => "bar/foo.html"). -pub fn render( - input: PathBuf, +pub fn render>( + input: P, options: RenderOptions, - diag: &rustc_errors::Handler, edition: Edition, -) -> i32 { +) -> Result<(), String> { if let Err(e) = create_dir_all(&options.output) { - diag.struct_err(&format!("{}: {}", options.output.display(), e)).emit(); - return 4; + return Err(format!("{}: {}", options.output.display(), e)); } + let input = input.as_ref(); let mut output = options.output; output.push(input.file_name().unwrap()); output.set_extension("html"); @@ -55,26 +54,15 @@ pub fn render( css.push_str(&s) } - let input_str = match load_string(&input, diag) { - Ok(s) => s, - Err(LoadStringError::ReadFail) => return 1, - Err(LoadStringError::BadUtf8) => return 2, - }; + let input_str = read_to_string(input).map_err(|err| format!("{}: {}", input.display(), err))?; let playground_url = options.markdown_playground_url.or(options.playground_url); let playground = playground_url.map(|url| markdown::Playground { crate_name: None, url }); - let mut out = match File::create(&output) { - Err(e) => { - diag.struct_err(&format!("{}: {}", output.display(), e)).emit(); - return 4; - } - Ok(f) => f, - }; + let mut out = File::create(&output).map_err(|e| format!("{}: {}", output.display(), e))?; let (metadata, text) = extract_leading_metadata(&input_str); if metadata.is_empty() { - diag.struct_err("invalid markdown file: no initial lines starting with `# ` or `%`").emit(); - return 5; + return Err("invalid markdown file: no initial lines starting with `# ` or `%`".to_owned()); } let title = metadata[0]; @@ -122,11 +110,8 @@ pub fn render( ); match err { - Err(e) => { - diag.struct_err(&format!("cannot write to `{}`: {}", output.display(), e)).emit(); - 6 - } - Ok(_) => 0, + Err(e) => Err(format!("cannot write to `{}`: {}", output.display(), e)), + Ok(_) => Ok(()), } } From e9c78db0861f6495f903a41e087c9628d777b87b Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Fri, 8 May 2020 22:48:26 +0200 Subject: [PATCH 014/695] Update annotate-snippets-rs to 0.8.0 --- Cargo.lock | 12 +- src/librustc_errors/Cargo.toml | 2 +- .../annotate_snippet_emitter_writer.rs | 204 +++++++----------- .../ui/annotate-snippet/missing-type.stderr | 2 +- 4 files changed, 92 insertions(+), 128 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 375e567222965..7e0448a152f4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,6 +48,12 @@ dependencies = [ "ansi_term", ] +[[package]] +name = "annotate-snippets" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5" + [[package]] name = "ansi_term" version = "0.11.0" @@ -3277,7 +3283,7 @@ version = "654.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "908e1ea187c6bb368af4ba6db980001e920515e67371ddc4086e749baabe6080" dependencies = [ - "annotate-snippets", + "annotate-snippets 0.6.1", "atty", "log", "rustc-ap-rustc_data_structures", @@ -3761,7 +3767,7 @@ version = "0.0.0" name = "rustc_errors" version = "0.0.0" dependencies = [ - "annotate-snippets", + "annotate-snippets 0.8.0", "atty", "log", "rustc_data_structures", @@ -4408,7 +4414,7 @@ dependencies = [ name = "rustfmt-nightly" version = "1.4.14" dependencies = [ - "annotate-snippets", + "annotate-snippets 0.6.1", "bytecount", "cargo_metadata 0.8.0", "derive-new", diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index b8340b1a1df6a..5882a6855b673 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -17,7 +17,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" -annotate-snippets = "0.6.1" +annotate-snippets = "0.8.0" termize = "0.1.1" [target.'cfg(windows)'.dependencies] diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs index d83175694f407..df5e43626aab9 100644 --- a/src/librustc_errors/annotate_snippet_emitter_writer.rs +++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs @@ -8,12 +8,11 @@ use crate::emitter::FileWithAnnotatedLines; use crate::snippet::Line; use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Emitter, Level, SubDiagnostic}; -use annotate_snippets::display_list::DisplayList; -use annotate_snippets::formatter::DisplayListFormatter; +use annotate_snippets::display_list::{DisplayList, FormatOptions}; use annotate_snippets::snippet::*; use rustc_data_structures::sync::Lrc; use rustc_span::source_map::SourceMap; -use rustc_span::{Loc, MultiSpan, SourceFile}; +use rustc_span::{MultiSpan, SourceFile}; /// Generates diagnostics using annotate-snippet pub struct AnnotateSnippetEmitterWriter { @@ -59,112 +58,20 @@ impl Emitter for AnnotateSnippetEmitterWriter { } } -/// Collects all the data needed to generate the data structures needed for the -/// `annotate-snippets` library. -struct DiagnosticConverter<'a> { - source_map: Option>, - level: Level, - message: String, - code: Option, - msp: MultiSpan, - #[allow(dead_code)] - children: &'a [SubDiagnostic], - #[allow(dead_code)] - suggestions: &'a [CodeSuggestion], +/// Provides the source string for the given `line` of `file` +fn source_string(file: Lrc, line: &Line) -> String { + file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default() } -impl<'a> DiagnosticConverter<'a> { - /// Turns rustc Diagnostic information into a `annotate_snippets::snippet::Snippet`. - fn to_annotation_snippet(&self) -> Option { - if let Some(source_map) = &self.source_map { - // Make sure our primary file comes first - let primary_lo = if let Some(ref primary_span) = self.msp.primary_span().as_ref() { - source_map.lookup_char_pos(primary_span.lo()) - } else { - // FIXME(#59346): Not sure when this is the case and what - // should be done if it happens - return None; - }; - let annotated_files = - FileWithAnnotatedLines::collect_annotations(&self.msp, &self.source_map); - let slices = self.slices_for_files(annotated_files, primary_lo); - - Some(Snippet { - title: Some(Annotation { - label: Some(self.message.to_string()), - id: self.code.clone().map(|c| match c { - DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val, - }), - annotation_type: Self::annotation_type_for_level(self.level), - }), - footer: vec![], - slices, - }) - } else { - // FIXME(#59346): Is it ok to return None if there's no source_map? - None - } - } - - fn slices_for_files( - &self, - annotated_files: Vec, - primary_lo: Loc, - ) -> Vec { - // FIXME(#64205): Provide a test case where `annotated_files` is > 1 - annotated_files - .iter() - .flat_map(|annotated_file| { - annotated_file - .lines - .iter() - .map(|line| { - let line_source = Self::source_string(annotated_file.file.clone(), &line); - Slice { - source: line_source, - line_start: line.line_index, - origin: Some(primary_lo.file.name.to_string()), - // FIXME(#59346): Not really sure when `fold` should be true or false - fold: false, - annotations: line - .annotations - .iter() - .map(|a| self.annotation_to_source_annotation(a.clone())) - .collect(), - } - }) - .collect::>() - }) - .collect::>() - } - - /// Turns a `crate::snippet::Annotation` into a `SourceAnnotation` - fn annotation_to_source_annotation( - &self, - annotation: crate::snippet::Annotation, - ) -> SourceAnnotation { - SourceAnnotation { - range: (annotation.start_col, annotation.end_col), - label: annotation.label.unwrap_or("".to_string()), - annotation_type: Self::annotation_type_for_level(self.level), - } - } - - /// Provides the source string for the given `line` of `file` - fn source_string(file: Lrc, line: &Line) -> String { - file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or(String::new()) - } - - /// Maps `Diagnostic::Level` to `snippet::AnnotationType` - fn annotation_type_for_level(level: Level) -> AnnotationType { - match level { - Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error, - Level::Warning => AnnotationType::Warning, - Level::Note => AnnotationType::Note, - Level::Help => AnnotationType::Help, - // FIXME(#59346): Not sure how to map these two levels - Level::Cancelled | Level::FailureNote => AnnotationType::Error, - } +/// Maps `Diagnostic::Level` to `snippet::AnnotationType` +fn annotation_type_for_level(level: Level) -> AnnotationType { + match level { + Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error, + Level::Warning => AnnotationType::Warning, + Level::Note => AnnotationType::Note, + Level::Help => AnnotationType::Help, + // FIXME(#59346): Not sure how to map these two levels + Level::Cancelled | Level::FailureNote => AnnotationType::Error, } } @@ -191,25 +98,76 @@ impl AnnotateSnippetEmitterWriter { message: String, code: &Option, msp: &MultiSpan, - children: &[SubDiagnostic], - suggestions: &[CodeSuggestion], + _children: &[SubDiagnostic], + _suggestions: &[CodeSuggestion], ) { - let converter = DiagnosticConverter { - source_map: self.source_map.clone(), - level: *level, - message, - code: code.clone(), - msp: msp.clone(), - children, - suggestions, - }; - if let Some(snippet) = converter.to_annotation_snippet() { - let dl = DisplayList::from(snippet); - let dlf = DisplayListFormatter::new(true, self.ui_testing); + if let Some(source_map) = &self.source_map { + // Make sure our primary file comes first + let primary_lo = if let Some(ref primary_span) = msp.primary_span().as_ref() { + source_map.lookup_char_pos(primary_span.lo()) + } else { + // FIXME(#59346): Not sure when this is the case and what + // should be done if it happens + return; + }; + let annotated_files = + FileWithAnnotatedLines::collect_annotations(msp, &self.source_map); + // owned: line source, line index, annotations + type Owned = (String, usize, Vec); + let origin = primary_lo.file.name.to_string(); + let annotated_files: Vec = annotated_files + .into_iter() + .flat_map(|annotated_file| { + let file = annotated_file.file; + annotated_file + .lines + .into_iter() + .map(|line| { + (source_string(file.clone(), &line), line.line_index, line.annotations) + }) + .collect::>() + }) + .collect(); + let snippet = Snippet { + title: Some(Annotation { + label: Some(&message), + id: code.as_ref().map(|c| match c { + DiagnosticId::Error(val) | DiagnosticId::Lint(val) => val.as_str(), + }), + annotation_type: annotation_type_for_level(*level), + }), + footer: vec![], + opt: FormatOptions { color: true, anonymized_line_numbers: self.ui_testing }, + slices: annotated_files + .iter() + .map(|(source, line_index, annotations)| { + Slice { + source, + line_start: *line_index, + origin: Some(&origin), + // FIXME(#59346): Not really sure when `fold` should be true or false + fold: false, + annotations: annotations + .into_iter() + .map(|annotation| SourceAnnotation { + range: (annotation.start_col, annotation.end_col), + label: annotation + .label + .as_ref() + .map(|s| s.as_str()) + .unwrap_or_default(), + annotation_type: annotation_type_for_level(*level), + }) + .collect(), + } + }) + .collect(), + }; // FIXME(#59346): Figure out if we can _always_ print to stderr or not. // `emitter.rs` has the `Destination` enum that lists various possible output // destinations. - eprintln!("{}", dlf.format(&dl)); - }; + eprintln!("{}", DisplayList::from(snippet)) + } + // FIXME(#59346): Is it ok to return None if there's no source_map? } } diff --git a/src/test/ui/annotate-snippet/missing-type.stderr b/src/test/ui/annotate-snippet/missing-type.stderr index 806acf0bed5d1..c16f022a77fa3 100644 --- a/src/test/ui/annotate-snippet/missing-type.stderr +++ b/src/test/ui/annotate-snippet/missing-type.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Iter` in this scope - --> $DIR/missing-type.rs:4:11 + --> $DIR/missing-type.rs:4:12 | LL | let x: Iter; | ^^^^ not found in this scope From bb433914b5bdd6898200f8c1cadcfec27fbf7a26 Mon Sep 17 00:00:00 2001 From: Erin Power Date: Sat, 9 May 2020 02:13:02 +0200 Subject: [PATCH 015/695] Update RELEASES.md for 1.44.0 --- RELEASES.md | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 8ea481f7e18cd..b2c4675908e07 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,134 @@ +Version 1.44.0 (2020-06-04) +========================== + +Language +-------- +- [You can now use `async/.await` with `#[no_std]` enabled.][69033] +- [Added the `unused_braces` lint.][70081] + +**Syntax-only changes** + +- [Expansion-driven outline module parsing][69838] + +These are still rejected semantically, so you will likely receive an error but +these changes can be seen and parsed by macros and conditional compilation. + +Compiler +-------- +- [Rustc now respects the `-C codegen-units` flag in incremental mode.][70156] + Additionally when incremental mode rustc defaults to 256 codegen units. +- [Added tier 3\* support for the `aarch64-unknown-none` and + `aarch64-unknown-none-softfloat` targets.][68334] +- [Refactored `catch_unwind`, to have zero-cost unless unwinding is enabled and + a panic is thrown.][67502] + +Libraries +--------- +- [Special cased `vec![]` to map directly to `Vec::new()`.][70632] This allows + `vec![]` to be able to be used in `const` contexts. +- [`convert::Infallible` now implements `Hash`.][70281] +- [`OsString` now implements `DerefMut` and `IndexMut` returning + a `&mut OsStr`.][70048] +- [Unicode 13 is now supported.][69929] +- [`String` now implements `From<&mut str>`.][69661] +- [`IoSlice` now implements `Copy`.][69403] +- [`Vec` now implements `From<[T; N]>`.][68692] Where `N` is less than 32. + +Stabilized APIs +--------------- +- [`PathBuf::with_capacity`] +- [`PathBuf::capacity`] +- [`PathBuf::clear`] +- [`PathBuf::reserve`] +- [`PathBuf::reserve_exact`] +- [`PathBuf::shrink_to_fit`] +- [`f32::to_int_unchecked`] +- [`f64::to_int_unchecked`] +- [`Layout::align_to`] +- [`Layout::pad_to_align`] +- [`Layout::array`] + +Cargo +----- +- [Added the `cargo tree` command which will print a tree graph of + your dependencies.][cargo/8062] E.g. + ``` + mdbook v0.3.2 (/Users/src/rust/mdbook) + ├── ammonia v3.0.0 + │ ├── html5ever v0.24.0 + │ │ ├── log v0.4.8 + │ │ │ └── cfg-if v0.1.9 + │ │ ├── mac v0.1.1 + │ │ └── markup5ever v0.9.0 + │ │ ├── log v0.4.8 (*) + │ │ ├── phf v0.7.24 + │ │ │ └── phf_shared v0.7.24 + │ │ │ ├── siphasher v0.2.3 + │ │ │ └── unicase v1.4.2 + │ │ │ [build-dependencies] + │ │ │ └── version_check v0.1.5 + ... + ``` + +Misc +---- +- [Rustdoc now allows you to specify `--crate-version` to have rustdoc include + the version in the sidebar.][69494] + +Compatibility Notes +------------------- +- [Rustc now correctly generates static libraries on Windows GNU targets with + the `.a` extension, rather than the previous `.lib`.][70937] +- [Removed the `-C no_integrated_as` flag from rustc.][70345] +- [The `file_name` property in JSON output of macro errors now points the actual + source file rather than the previous format of ``.][70969] + **Note:** this may not point a file that actually exists on the user's system. +- [The minimum required external LLVM version has been bumped to LLVM 8.][71147] + +Internal Only +------------- +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc and +related tools. + +- [dep_graph Avoid allocating a set on when the number reads are small.][69778] +- [Replace big JS dict with JSON parsing.][71250] + + +[71147]: https://github.com/rust-lang/rust/pull/71147/ +[71250]: https://github.com/rust-lang/rust/pull/71250/ +[70937]: https://github.com/rust-lang/rust/pull/70937/ +[70969]: https://github.com/rust-lang/rust/pull/70969/ +[70632]: https://github.com/rust-lang/rust/pull/70632/ +[70281]: https://github.com/rust-lang/rust/pull/70281/ +[70345]: https://github.com/rust-lang/rust/pull/70345/ +[70048]: https://github.com/rust-lang/rust/pull/70048/ +[70081]: https://github.com/rust-lang/rust/pull/70081/ +[70156]: https://github.com/rust-lang/rust/pull/70156/ +[69838]: https://github.com/rust-lang/rust/pull/69838/ +[69929]: https://github.com/rust-lang/rust/pull/69929/ +[69661]: https://github.com/rust-lang/rust/pull/69661/ +[69778]: https://github.com/rust-lang/rust/pull/69778/ +[69494]: https://github.com/rust-lang/rust/pull/69494/ +[69403]: https://github.com/rust-lang/rust/pull/69403/ +[69033]: https://github.com/rust-lang/rust/pull/69033/ +[68692]: https://github.com/rust-lang/rust/pull/68692/ +[68334]: https://github.com/rust-lang/rust/pull/68334/ +[67502]: https://github.com/rust-lang/rust/pull/67502/ +[cargo/8062]: https://github.com/rust-lang/cargo/pull/8062/ +[`PathBuf::with_capacity`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.with_capacity +[`PathBuf::capacity`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.capacity +[`PathBuf::clear`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.clear +[`PathBuf::reserve`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.reserve +[`PathBuf::reserve_exact`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.reserve_exact +[`PathBuf::shrink_to_fit`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.shrink_to_fit +[`f32::to_int_unchecked`]: https://doc.rust-lang.org/beta/std/primitive.f32.html#method.to_int_unchecked +[`f64::to_int_unchecked`]: https://doc.rust-lang.org/beta/std/primitive.f64.html#method.to_int_unchecked +[`Layout::align_to`]: https://doc.rust-lang.org/beta/std/alloc/struct.Layout.html#method.align_to +[`Layout::pad_to_align`]: https://doc.rust-lang.org/beta/std/alloc/struct.Layout.html#method.pad_to_align +[`Layout::array`]: https://doc.rust-lang.org/beta/std/alloc/struct.Layout.html#method.array + + Version 1.43.1 (2020-05-07) =========================== From c8fb0d7ef38957cd2b8f6e5b9b7ea47eaa6cca28 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 9 May 2020 13:37:26 +0200 Subject: [PATCH 016/695] End unification of exit codes in librustdoc --- src/librustdoc/lib.rs | 27 ++++++++++++++++++--------- src/librustdoc/markdown.rs | 13 ++++--------- src/librustdoc/test.rs | 6 +++--- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 8e5dfbeeda5f4..82d6cda986a9a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -450,20 +450,29 @@ fn main_args(args: &[String]) -> i32 { rustc_interface::interface::default_thread_pool(options.edition, move || main_options(options)) } +fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> i32 { + match res { + Ok(()) => 0, + Err(err) => { + if !err.is_empty() { + diag.struct_err(&err).emit(); + } + 1 + } + } +} + fn main_options(options: config::Options) -> i32 { let diag = core::new_handler(options.error_format, None, &options.debugging_options); match (options.should_test, options.markdown_input()) { - (true, true) => return markdown::test(options, &diag), - (true, false) => return test::run(options), + (true, true) => return wrap_return(&diag, markdown::test(options)), + (true, false) => return wrap_return(&diag, test::run(options)), (false, true) => { - match markdown::render(&options.input, options.render_options, options.edition) { - Ok(()) => return 0, - Err(err) => { - diag.struct_err(&err).emit(); - return 1; - } - } + return wrap_return( + &diag, + markdown::render(&options.input, options.render_options, options.edition), + ); } (false, false) => {} } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 1977d3653ba23..e0753bcd70f29 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -7,7 +7,6 @@ use rustc_span::edition::Edition; use rustc_span::source_map::DUMMY_SP; use crate::config::{Options, RenderOptions}; -use crate::externalfiles::{load_string, LoadStringError}; use crate::html::escape::Escape; use crate::html::markdown; use crate::html::markdown::{find_testable_code, ErrorCodes, IdMap, Markdown, MarkdownWithToc}; @@ -116,13 +115,9 @@ pub fn render>( } /// Runs any tests/code examples in the markdown file `input`. -pub fn test(mut options: Options, diag: &rustc_errors::Handler) -> i32 { - let input_str = match load_string(&options.input, diag) { - Ok(s) => s, - Err(LoadStringError::ReadFail) => return 1, - Err(LoadStringError::BadUtf8) => return 2, - }; - +pub fn test(mut options: Options) -> Result<(), String> { + let input_str = read_to_string(&options.input) + .map_err(|err| format!("{}: {}", options.input.display(), err))?; let mut opts = TestOptions::default(); opts.no_crate_inject = true; opts.display_warnings = options.display_warnings; @@ -146,5 +141,5 @@ pub fn test(mut options: Options, diag: &rustc_errors::Handler) -> i32 { collector.tests, Some(testing::Options::new().display_output(options.display_warnings)), ); - 0 + Ok(()) } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 5028bb46b0066..4253318e35fc1 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -42,7 +42,7 @@ pub struct TestOptions { pub attrs: Vec, } -pub fn run(options: Options) -> i32 { +pub fn run(options: Options) -> Result<(), String> { let input = config::Input::File(options.input.clone()); let warnings_lint_name = lint::builtin::WARNINGS.name; @@ -175,7 +175,7 @@ pub fn run(options: Options) -> i32 { }); let tests = match tests { Ok(tests) => tests, - Err(ErrorReported) => return 1, + Err(ErrorReported) => return Err(String::new()), }; test_args.insert(0, "rustdoctest".to_string()); @@ -186,7 +186,7 @@ pub fn run(options: Options) -> i32 { Some(testing::Options::new().display_output(display_warnings)), ); - 0 + Ok(()) } // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. From bd5ed9e62f330971523fb75390b4a375bc1d875c Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Sat, 9 May 2020 16:30:00 +0200 Subject: [PATCH 017/695] Update RELEASES.md Co-authored-by: Jonas Schievink --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index b2c4675908e07..132e8a6d94850 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -16,7 +16,7 @@ these changes can be seen and parsed by macros and conditional compilation. Compiler -------- - [Rustc now respects the `-C codegen-units` flag in incremental mode.][70156] - Additionally when incremental mode rustc defaults to 256 codegen units. + Additionally when in incremental mode rustc defaults to 256 codegen units. - [Added tier 3\* support for the `aarch64-unknown-none` and `aarch64-unknown-none-softfloat` targets.][68334] - [Refactored `catch_unwind`, to have zero-cost unless unwinding is enabled and From a8c152dfc921e8ec2c00f65e7c731197e522a96d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 9 May 2020 22:01:15 +0200 Subject: [PATCH 018/695] add regression tests + improve method name --- .../traits/fulfill.rs | 8 ++--- .../issue-70180-1-stalled_on.rs | 35 +++++++++++++++++++ .../issue-70180-2-stalled_on.rs | 35 +++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/const-generics/issue-70180-1-stalled_on.rs create mode 100644 src/test/ui/const-generics/issue-70180-2-stalled_on.rs diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 1e056c96acd38..dfffdbedf4ca4 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -355,7 +355,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { // trait selection is because we don't have enough // information about the types in the trait. pending_obligation.stalled_on = - trait_ref_type_vars(self.selcx, data.to_poly_trait_ref()); + trait_ref_infer_vars(self.selcx, data.to_poly_trait_ref()); debug!( "process_predicate: pending obligation {:?} now stalled on {:?}", @@ -433,7 +433,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { Ok(None) => { let tcx = self.selcx.tcx(); pending_obligation.stalled_on = - trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx)); + trait_ref_infer_vars(self.selcx, data.to_poly_trait_ref(tcx)); ProcessResult::Unchanged } Ok(Some(os)) => ProcessResult::Changed(mk_pending(infcx, os)), @@ -539,8 +539,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } -/// Returns the set of type inference variables contained in a trait ref. -fn trait_ref_type_vars<'a, 'tcx>( +/// Returns the set of inference variables contained in a trait ref. +fn trait_ref_infer_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Vec> { diff --git a/src/test/ui/const-generics/issue-70180-1-stalled_on.rs b/src/test/ui/const-generics/issue-70180-1-stalled_on.rs new file mode 100644 index 0000000000000..ff2a5250263d5 --- /dev/null +++ b/src/test/ui/const-generics/issue-70180-1-stalled_on.rs @@ -0,0 +1,35 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +pub fn works() { + let array/*: [_; _]*/ = default_array(); + let _: [_; 4] = array; + Foo::foo(&array); +} + +pub fn didnt_work() { + let array/*: [_; _]*/ = default_array(); + Foo::foo(&array); + let _: [_; 4] = array; +} + +trait Foo { + fn foo(&self) {} +} + +impl Foo for [i32; 4] {} +impl Foo for [i64; 8] {} + +// Only needed because `[_; _]` is not valid type syntax. +fn default_array() -> [T; N] +where + [T; N]: Default, +{ + Default::default() +} + +fn main() { + works(); + didnt_work(); +} diff --git a/src/test/ui/const-generics/issue-70180-2-stalled_on.rs b/src/test/ui/const-generics/issue-70180-2-stalled_on.rs new file mode 100644 index 0000000000000..83338668f4ffd --- /dev/null +++ b/src/test/ui/const-generics/issue-70180-2-stalled_on.rs @@ -0,0 +1,35 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn works() { + let array/*: [u8; _]*/ = default_byte_array(); + let _: [_; 4] = array; + Foo::foo(&array); +} + +fn didnt_work() { + let array/*: [u8; _]*/ = default_byte_array(); + Foo::foo(&array); + let _: [_; 4] = array; +} + +trait Foo { + fn foo(&self) {} +} + +impl Foo for [u8; 4] {} +impl Foo for [u8; 8] {} + +// Only needed because `[u8; _]` is not valid type syntax. +fn default_byte_array() -> [u8; N] +where + [u8; N]: Default, +{ + Default::default() +} + +fn main() { + works(); + didnt_work(); +} From f16060f386c3ceee257b2c38ce5072b2d0943b6a Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Sun, 10 May 2020 01:25:30 +0200 Subject: [PATCH 019/695] Add UI test where `annotated_files` count is > 1 #64205 --- .../annotate-snippet/auxiliary/multispan.rs | 37 ++++++++++++++++ src/test/ui/annotate-snippet/multispan.rs | 28 +++++++++++++ src/test/ui/annotate-snippet/multispan.stderr | 42 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 src/test/ui/annotate-snippet/auxiliary/multispan.rs create mode 100644 src/test/ui/annotate-snippet/multispan.rs create mode 100644 src/test/ui/annotate-snippet/multispan.stderr diff --git a/src/test/ui/annotate-snippet/auxiliary/multispan.rs b/src/test/ui/annotate-snippet/auxiliary/multispan.rs new file mode 100644 index 0000000000000..c05d15643dbb1 --- /dev/null +++ b/src/test/ui/annotate-snippet/auxiliary/multispan.rs @@ -0,0 +1,37 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_diagnostic, proc_macro_span, proc_macro_def_site)] + +extern crate proc_macro; + +use proc_macro::{TokenStream, TokenTree, Span, Diagnostic}; + +fn parse(input: TokenStream) -> Result<(), Diagnostic> { + let mut hi_spans = vec![]; + for tree in input { + if let TokenTree::Ident(ref ident) = tree { + if ident.to_string() == "hi" { + hi_spans.push(ident.span()); + } + } + } + + if !hi_spans.is_empty() { + return Err(Span::def_site() + .error("hello to you, too!") + .span_note(hi_spans, "found these 'hi's")); + } + + Ok(()) +} + +#[proc_macro] +pub fn hello(input: TokenStream) -> TokenStream { + if let Err(diag) = parse(input) { + diag.emit(); + } + + TokenStream::new() +} diff --git a/src/test/ui/annotate-snippet/multispan.rs b/src/test/ui/annotate-snippet/multispan.rs new file mode 100644 index 0000000000000..325252d7716f6 --- /dev/null +++ b/src/test/ui/annotate-snippet/multispan.rs @@ -0,0 +1,28 @@ +// aux-build:multispan.rs +// compile-flags: --error-format human-annotate-rs + +#![feature(proc_macro_hygiene)] + +extern crate multispan; + +use multispan::hello; + +fn main() { + // This one emits no error. + hello!(); + + // Exactly one 'hi'. + hello!(hi); //~ ERROR hello to you, too! + + // Now two, back to back. + hello!(hi hi); //~ ERROR hello to you, too! + + // Now three, back to back. + hello!(hi hi hi); //~ ERROR hello to you, too! + + // Now several, with spacing. + hello!(hi hey hi yo hi beep beep hi hi); //~ ERROR hello to you, too! + hello!(hi there, hi how are you? hi... hi.); //~ ERROR hello to you, too! + hello!(whoah. hi di hi di ho); //~ ERROR hello to you, too! + hello!(hi good hi and good bye); //~ ERROR hello to you, too! +} diff --git a/src/test/ui/annotate-snippet/multispan.stderr b/src/test/ui/annotate-snippet/multispan.stderr new file mode 100644 index 0000000000000..4ac31e32ba7cf --- /dev/null +++ b/src/test/ui/annotate-snippet/multispan.stderr @@ -0,0 +1,42 @@ +error: hello to you, too! + --> $DIR/multispan.rs:15:5 + | +LL | hello!(hi); + | ^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:18:5 + | +LL | hello!(hi hi); + | ^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:21:5 + | +LL | hello!(hi hi hi); + | ^^^^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:24:5 + | +LL | hello!(hi hey hi yo hi beep beep hi hi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:25:5 + | +LL | hello!(hi there, hi how are you? hi... hi.); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:26:5 + | +LL | hello!(whoah. hi di hi di ho); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +error: hello to you, too! + --> $DIR/multispan.rs:27:5 + | +LL | hello!(hi good hi and good bye); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | From 510fce10f8a22521ec861f4446a304f9a2e4c5bd Mon Sep 17 00:00:00 2001 From: Jubilee <46493976+workingjubilee@users.noreply.github.com> Date: Sun, 10 May 2020 14:59:38 -0700 Subject: [PATCH 020/695] Unblock font loading in rustdoc.css rustdoc's font loading defaults to "auto", so browsers may block render. But rustdoc's case prefers a faster TTI for scrolling, this means the strictest font-display in use should be "swap". rustdoc's fonts do provide notable legibility improvements but first-time users will have little trouble reading without. This means "optional" is preferred. The one exception is Source Serif Pro: it's a big difference for body text, so "fallback" is preferred over "optional" to cause a (tiny) block. --- src/librustdoc/html/static/rustdoc.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index ab52475172333..b1faa8e83e595 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -3,12 +3,14 @@ font-family: 'Fira Sans'; font-style: normal; font-weight: 400; + font-display: optional; src: local('Fira Sans'), url("FiraSans-Regular.woff") format('woff'); } @font-face { font-family: 'Fira Sans'; font-style: normal; font-weight: 500; + font-display: optional; src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff'); } @@ -17,18 +19,23 @@ font-family: 'Source Serif Pro'; font-style: normal; font-weight: 400; + /* The difference for body text without this font is greater than other fonts, + * so the 0~100ms block of fallback is preferred over optional, for legibility. */ + font-display: fallback; src: local('Source Serif Pro'), url("SourceSerifPro-Regular.ttf.woff") format('woff'); } @font-face { font-family: 'Source Serif Pro'; font-style: italic; font-weight: 400; + font-display: optional; src: local('Source Serif Pro Italic'), url("SourceSerifPro-It.ttf.woff") format('woff'); } @font-face { font-family: 'Source Serif Pro'; font-style: normal; font-weight: 700; + font-display: optional; src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.ttf.woff") format('woff'); } @@ -37,6 +44,7 @@ font-family: 'Source Code Pro'; font-style: normal; font-weight: 400; + font-display: optional; /* Avoid using locally installed font because bad versions are in circulation: * see https://github.com/rust-lang/rust/issues/24355 */ src: url("SourceCodePro-Regular.woff") format('woff'); @@ -45,6 +53,7 @@ font-family: 'Source Code Pro'; font-style: normal; font-weight: 600; + font-display: optional; src: url("SourceCodePro-Semibold.woff") format('woff'); } From 318b8b6aabb2ef0fae0c0aafbba2c7ad97fb3a2a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 10 May 2020 22:15:04 -0400 Subject: [PATCH 021/695] Add hint for collect type --- clippy_lints/src/utils/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index f7a91fcdd213a..8d75e1269630d 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1390,7 +1390,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_, '_>, did: DefId) -> bool .predicates .iter() .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }) - .collect(); + .collect::>(); !traits::normalize_and_test_predicates( cx.tcx, traits::elaborate_predicates(cx.tcx, predicates) From 3f661d25f9ce3b5ac6139c8d8bf4614b55dca5be Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 10:29:05 +0200 Subject: [PATCH 022/695] borrowck `DefId` -> `LocalDefId` --- .../diagnostics/conflict_errors.rs | 89 +++++++++---------- .../borrow_check/diagnostics/move_errors.rs | 2 +- .../diagnostics/mutability_errors.rs | 2 +- .../borrow_check/diagnostics/region_errors.rs | 2 +- .../borrow_check/diagnostics/region_name.rs | 9 +- src/librustc_mir/borrow_check/mod.rs | 14 ++- src/librustc_mir/borrow_check/nll.rs | 8 +- 7 files changed, 59 insertions(+), 67 deletions(-) diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 5f1c0911da2bf..d0050f801fc6b 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -214,7 +214,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let generics = tcx.generics_of(self.mir_def_id); let param = generics.type_param(¶m_ty, tcx); if let Some(generics) = - tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id)) + tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id.to_def_id())) { suggest_constraining_type_param( tcx, @@ -865,49 +865,42 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("`{}` would have to be valid for `{}`...", name, region_name), ); - if let Some(def_id) = self.mir_def_id.as_local() { - let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id); - err.span_label( - drop_span, - format!( - "...but `{}` will be dropped here, when the {} returns", - name, - self.infcx - .tcx - .hir() - .opt_name(fn_hir_id) - .map(|name| format!("function `{}`", name)) - .unwrap_or_else(|| { - match &self - .infcx - .tcx - .typeck_tables_of(def_id) - .node_type(fn_hir_id) - .kind - { - ty::Closure(..) => "enclosing closure", - ty::Generator(..) => "enclosing generator", - kind => bug!("expected closure or generator, found {:?}", kind), - } - .to_string() - }) - ), - ); + let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id); + err.span_label( + drop_span, + format!( + "...but `{}` will be dropped here, when the {} returns", + name, + self.infcx + .tcx + .hir() + .opt_name(fn_hir_id) + .map(|name| format!("function `{}`", name)) + .unwrap_or_else(|| { + match &self + .infcx + .tcx + .typeck_tables_of(self.mir_def_id) + .node_type(fn_hir_id) + .kind + { + ty::Closure(..) => "enclosing closure", + ty::Generator(..) => "enclosing generator", + kind => bug!("expected closure or generator, found {:?}", kind), + } + .to_string() + }) + ), + ); - err.note( - "functions cannot return a borrow to data owned within the function's scope, \ - functions can only return borrows to data passed as arguments", - ); - err.note( - "to learn more, visit ", - ); - } else { - err.span_label( - drop_span, - format!("...but `{}` dropped here while still borrowed", name), - ); - } + err.note( + "functions cannot return a borrow to data owned within the function's scope, \ + functions can only return borrows to data passed as arguments", + ); + err.note( + "to learn more, visit ", + ); if let BorrowExplanation::MustBeValidFor { .. } = explanation { } else { @@ -1237,7 +1230,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> DiagnosticBuilder<'cx> { let tcx = self.infcx.tcx; - let (_, escapes_from) = tcx.article_and_description(self.mir_def_id); + let (_, escapes_from) = tcx.article_and_description(self.mir_def_id.to_def_id()); let mut err = borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from); @@ -1572,14 +1565,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> Option> { // Define a fallback for when we can't match a closure. let fallback = || { - let is_closure = self.infcx.tcx.is_closure(self.mir_def_id); + let is_closure = self.infcx.tcx.is_closure(self.mir_def_id.to_def_id()); if is_closure { None } else { let ty = self.infcx.tcx.type_of(self.mir_def_id); match ty.kind { - ty::FnDef(_, _) | ty::FnPtr(_) => self - .annotate_fn_sig(self.mir_def_id, self.infcx.tcx.fn_sig(self.mir_def_id)), + ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( + self.mir_def_id.to_def_id(), + self.infcx.tcx.fn_sig(self.mir_def_id), + ), _ => None, } } diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index 67254811ec52a..b49e4187fb810 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -331,7 +331,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.cannot_move_out_of_interior_noncopy(span, ty, None) } ty::Closure(def_id, closure_substs) - if def_id == self.mir_def_id && upvar_field.is_some() => + if def_id.as_local() == Some(self.mir_def_id) && upvar_field.is_some() => { let closure_kind_ty = closure_substs.as_closure().kind_ty(); let closure_kind = closure_kind_ty.to_opt_closure_kind(); diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index 402eac47c462b..e04ed8b83debd 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -492,7 +492,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_label(sp, format!("cannot {}", act)); let hir = self.infcx.tcx.hir(); - let closure_id = hir.as_local_hir_id(self.mir_def_id.expect_local()); + let closure_id = hir.as_local_hir_id(self.mir_def_id); let fn_call_id = hir.get_parent_node(closure_id); let node = hir.get(fn_call_id); let item_id = hir.get_parent_item(fn_call_id); diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 98c0542f9c0dc..f24d668739949 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -502,7 +502,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut diag = self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough"); - let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id); + let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id.to_def_id()); let fr_name = self.give_region_a_name(*fr).unwrap(); fr_name.highlight_region_name(&mut diag); diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs index 37e2e0475048d..aee825a811380 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs @@ -237,8 +237,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } ty::BoundRegion::BrEnv => { - let mir_hir_id = - self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id.expect_local()); + let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id); let def_ty = self.regioncx.universal_regions().defining_ty; if let DefiningTy::Closure(_, substs) = def_ty { @@ -324,7 +323,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { argument_ty: Ty<'tcx>, argument_index: usize, ) -> Option { - let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id.as_local()?); + let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id); let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?; let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?; match argument_hir_ty.kind { @@ -635,7 +634,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0; - let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id.expect_local()); + let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id); let (return_span, mir_description) = match tcx.hir().get(mir_hir_id) { hir::Node::Expr(hir::Expr { @@ -687,7 +686,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0; - let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id.expect_local()); + let mir_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id); let yield_span = match tcx.hir().get(mir_hir_id) { hir::Node::Expr(hir::Expr { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index d3ab7df817b38..baba3cb1babcc 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -4,10 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; -use rustc_hir::{ - def_id::{DefId, LocalDefId}, - HirId, Node, -}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{HirId, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -174,7 +172,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut body = input_body.clone(); let mut promoted = input_promoted.clone(); let free_regions = - nll::replace_regions_in_mir(infcx, def_id.to_def_id(), param_env, &mut body, &mut promoted); + nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted); let body = &body; // no further changes let location_table = &LocationTable::new(&body); @@ -275,7 +273,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut promoted_mbcx = MirBorrowckCtxt { infcx, body: promoted_body, - mir_def_id: def_id.to_def_id(), + mir_def_id: def_id, move_data: &move_data, location_table: &LocationTable::new(promoted_body), movable_generator, @@ -307,7 +305,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut mbcx = MirBorrowckCtxt { infcx, body, - mir_def_id: def_id.to_def_id(), + mir_def_id: def_id, move_data: &mdpe.move_data, location_table, movable_generator, @@ -459,7 +457,7 @@ fn do_mir_borrowck<'a, 'tcx>( crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, body: &'cx Body<'tcx>, - mir_def_id: DefId, + mir_def_id: LocalDefId, move_data: &'cx MoveData<'tcx>, /// Map from MIR `Location` to `LocationIndex`; created diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index 29636a067092b..eb453c4bb7b3b 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::Diagnostic; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{ @@ -58,7 +58,7 @@ crate struct NllOutput<'tcx> { /// `compute_regions`. pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, - def_id: DefId, + def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec>, @@ -66,12 +66,12 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( debug!("replace_regions_in_mir(def_id={:?})", def_id); // Compute named region information. This also renumbers the inputs/outputs. - let universal_regions = UniversalRegions::new(infcx, def_id.expect_local(), param_env); + let universal_regions = UniversalRegions::new(infcx, def_id, param_env); // Replace all remaining regions with fresh inference variables. renumber::renumber_mir(infcx, body, promoted); - let source = MirSource::item(def_id); + let source = MirSource::item(def_id.to_def_id()); mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(())); universal_regions From c85768ed71eb09689e2065b122310dad2e1c42f6 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Mon, 11 May 2020 10:37:35 -0700 Subject: [PATCH 023/695] Update the Fuchsia linker defaults This updates the linker defaults aligning them with Clang. Specifically, we use 4K pages on all platforms, we always use BIND_NOW, we prefer all loadable segments be separate and page aligned, and we support RELR relocations. --- src/librustc_target/spec/fuchsia_base.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/librustc_target/spec/fuchsia_base.rs b/src/librustc_target/spec/fuchsia_base.rs index 4060b126cddb7..48d33953da5fa 100644 --- a/src/librustc_target/spec/fuchsia_base.rs +++ b/src/librustc_target/spec/fuchsia_base.rs @@ -9,7 +9,14 @@ pub fn opts() -> TargetOptions { "--eh-frame-hdr".to_string(), "--hash-style=gnu".to_string(), "-z".to_string(), + "max-page-size=4096".to_string(), + "-z".to_string(), + "now".to_string(), + "-z".to_string(), "rodynamic".to_string(), + "-z".to_string(), + "separate-loadable-segments".to_string(), + "--pack-dyn-relocs=relr".to_string(), ], ); From 5bfb7e7437dac924825be123f7c9645b4e4367e5 Mon Sep 17 00:00:00 2001 From: bdbai Date: Tue, 12 May 2020 16:33:41 +0800 Subject: [PATCH 024/695] Add target thumbv7a-uwp-windows-msvc --- src/librustc_codegen_ssa/back/link.rs | 1 + src/librustc_target/spec/mod.rs | 1 + .../spec/thumbv7a_uwp_windows_msvc.rs | 30 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index d8b38cf33707c..a035998030acc 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -181,6 +181,7 @@ fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command { "x86_64" => Some("x64".to_string()), "x86" => Some("x86".to_string()), "aarch64" => Some("arm64".to_string()), + "arm" => Some("arm".to_string()), _ => None, }; if let Some(ref a) = arch { diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 477161dc658d9..4e0530f53d7e9 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -530,6 +530,7 @@ supported_targets! { ("i686-uwp-windows-msvc", i686_uwp_windows_msvc), ("i586-pc-windows-msvc", i586_pc_windows_msvc), ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc), + ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc), ("asmjs-unknown-emscripten", asmjs_unknown_emscripten), ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), diff --git a/src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs b/src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs new file mode 100644 index 0000000000000..ff2e892100607 --- /dev/null +++ b/src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs @@ -0,0 +1,30 @@ +use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::windows_uwp_msvc_base::opts(); + base.max_atomic_width = Some(64); + base.has_elf_tls = true; + + // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is + // implemented for windows/arm in LLVM + base.panic_strategy = PanicStrategy::Abort; + + Ok(Target { + llvm_target: "thumbv7a-pc-windows-msvc".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "windows".to_string(), + target_env: "msvc".to_string(), + target_vendor: "uwp".to_string(), + linker_flavor: LinkerFlavor::Msvc, + options: TargetOptions { + features: "+vfp3,+neon".to_string(), + cpu: "generic".to_string(), + abi_blacklist: super::arm_base::abi_blacklist(), + ..base + }, + }) +} From 29a41f0d86b82c2731cc2ab8c8a26272e773e4c3 Mon Sep 17 00:00:00 2001 From: csmoe Date: Mon, 11 May 2020 14:24:57 +0800 Subject: [PATCH 025/695] add ui test for issue-69276 --- src/librustc_typeck/check/mod.rs | 6 +++++- src/test/ui/async-await/issue-69276.rs | 12 ++++++++++++ src/test/ui/async-await/issue-69276.stderr | 8 ++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/async-await/issue-69276.rs create mode 100644 src/test/ui/async-await/issue-69276.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 956e09ec52b4a..57fdb03250e7a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1659,6 +1659,7 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, let prohibit_opaque = match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { + bounds, origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, .. }) => { @@ -1671,6 +1672,9 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, }; debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor); + for bound in bounds { + debug!("check_opaque_for_inheriting_lifetimes: {:?}", bound.trait_ref()); + } tcx.predicates_of(def_id) .predicates .iter() @@ -1695,7 +1699,7 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ a parent scope", if is_async { "async fn" } else { "impl Trait" }, - ), + ) ); } } diff --git a/src/test/ui/async-await/issue-69276.rs b/src/test/ui/async-await/issue-69276.rs new file mode 100644 index 0000000000000..224b76e2d903f --- /dev/null +++ b/src/test/ui/async-await/issue-69276.rs @@ -0,0 +1,12 @@ +// edition:2018 + +struct S<'a>(&'a i32); + +impl<'a> S<'a> { + async fn new(i: &'a i32) -> Self { + //~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + S(&22) + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-69276.stderr b/src/test/ui/async-await/issue-69276.stderr new file mode 100644 index 0000000000000..1ebfdfa8b54c5 --- /dev/null +++ b/src/test/ui/async-await/issue-69276.stderr @@ -0,0 +1,8 @@ +error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope + --> $DIR/issue-69276.rs:6:33 + | +LL | async fn new(i: &'a i32) -> Self { + | ^^^^ + +error: aborting due to previous error + From ff9646c0adc149dfff194665785f4daa3aa6d9c3 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 11 May 2020 17:19:25 -0700 Subject: [PATCH 026/695] Stabilize process_set_argv0 feature for Unix This stabilizes process_set_argv0 targeting 1.45.0. It has been useful in practice and seems useful as-is. The equivalent feature could be implemented for Windows, but as far as I know nobody has. That can be done separately. Tracking issue: #66510 --- src/libstd/sys/unix/ext/process.rs | 2 +- src/libstd/sys/vxworks/ext/process.rs | 2 +- src/test/ui/command/command-argv0-debug.rs | 2 -- src/test/ui/command/command-argv0.rs | 2 -- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index fa8670b4aecac..048ce24d6ba88 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -111,7 +111,7 @@ pub trait CommandExt { /// /// Set the first process argument, `argv[0]`, to something other than the /// default executable path. - #[unstable(feature = "process_set_argv0", issue = "66510")] + #[stable(feature = "process_set_argv0", since = "1.45.0")] fn arg0(&mut self, arg: S) -> &mut process::Command where S: AsRef; diff --git a/src/libstd/sys/vxworks/ext/process.rs b/src/libstd/sys/vxworks/ext/process.rs index 31e691dd1360b..c3710f4b9124d 100644 --- a/src/libstd/sys/vxworks/ext/process.rs +++ b/src/libstd/sys/vxworks/ext/process.rs @@ -111,7 +111,7 @@ pub trait CommandExt { /// /// Set the first process argument, `argv[0]`, to something other than the /// default executable path. - #[unstable(feature = "process_set_argv0", issue = "66510")] + #[stable(feature = "process_set_argv0", since = "1.45.0")] fn arg0(&mut self, arg: S) -> &mut process::Command where S: AsRef; diff --git a/src/test/ui/command/command-argv0-debug.rs b/src/test/ui/command/command-argv0-debug.rs index 133d2ada2b263..cb948a91c1054 100644 --- a/src/test/ui/command/command-argv0-debug.rs +++ b/src/test/ui/command/command-argv0-debug.rs @@ -4,8 +4,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes -#![feature(process_set_argv0)] - use std::os::unix::process::CommandExt; use std::process::Command; diff --git a/src/test/ui/command/command-argv0.rs b/src/test/ui/command/command-argv0.rs index 56a9fb4d39125..e3394e0567cb8 100644 --- a/src/test/ui/command/command-argv0.rs +++ b/src/test/ui/command/command-argv0.rs @@ -4,8 +4,6 @@ // ignore-cloudabi no processes // ignore-emscripten no processes // ignore-sgx no processes -#![feature(process_set_argv0)] - use std::env; use std::os::unix::process::CommandExt; use std::process::Command; From a3f30bbc2d28572f9fa429cf3b31d7f95d3b0dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 May 2020 10:56:26 -0700 Subject: [PATCH 027/695] Don't `type_of` on trait assoc ty without default Fix #72076. --- src/librustc_middle/ty/error.rs | 13 +++---- src/test/ui/issues/issue-72076.rs | 6 +++ src/test/ui/issues/issue-72076.stderr | 14 +++++++ ...ith-missing-associated-type-restriction.rs | 1 + ...missing-associated-type-restriction.stderr | 37 ++++++++++++++----- 5 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 src/test/ui/issues/issue-72076.rs create mode 100644 src/test/ui/issues/issue-72076.stderr diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs index f3b6a53dfeb82..00be12f46fe21 100644 --- a/src/librustc_middle/ty/error.rs +++ b/src/librustc_middle/ty/error.rs @@ -817,19 +817,18 @@ fn foo(&self) -> Self::T { String::new() } for item in &items[..] { match item.kind { hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => { - if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { - if let hir::Defaultness::Default { has_value: true } = - item.defaultness - { + // FIXME: account for returning some type in a trait fn impl that has + // an assoc type as a return type (#72076). + if let hir::Defaultness::Default { has_value: true } = item.defaultness + { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { db.span_label( item.span, "associated type defaults can't be assumed inside the \ trait defining them", ); - } else { - db.span_label(item.span, "expected this associated type"); + return true; } - return true; } } _ => {} diff --git a/src/test/ui/issues/issue-72076.rs b/src/test/ui/issues/issue-72076.rs new file mode 100644 index 0000000000000..1659044a64fe1 --- /dev/null +++ b/src/test/ui/issues/issue-72076.rs @@ -0,0 +1,6 @@ +trait X { + type S; + fn f() -> Self::S {} //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/issues/issue-72076.stderr b/src/test/ui/issues/issue-72076.stderr new file mode 100644 index 0000000000000..b942cf75b06a7 --- /dev/null +++ b/src/test/ui/issues/issue-72076.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-72076.rs:3:23 + | +LL | fn f() -> Self::S {} + | ^^ expected associated type, found `()` + | + = note: expected associated type `::S` + found unit type `()` + = help: consider constraining the associated type `::S` to `()` or calling a method that returns `::S` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs index 7465049787f59..0d90e449523a3 100644 --- a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs @@ -7,6 +7,7 @@ trait Trait { fn func(&self) -> Self::A; fn funk(&self, _: Self::A); + fn funq(&self) -> Self::A {} //~ ERROR mismatched types } fn foo(_: impl Trait, x: impl Trait) { diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr index 5ae1d45c6b703..e629f8f970d32 100644 --- a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr @@ -1,5 +1,19 @@ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:13:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:10:31 + | +LL | fn funq(&self) -> Self::A {} + | ^^ expected associated type, found `()` + | + = note: expected associated type `>::A` + found unit type `()` +help: a method is available that returns `>::A` + --> $DIR/trait-with-missing-associated-type-restriction.rs:8:5 + | +LL | fn func(&self) -> Self::A; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func` + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:14:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -12,7 +26,7 @@ LL | fn foo(_: impl Trait, x: impl Trait) { | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:17:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:18:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -25,7 +39,7 @@ LL | fn bar>(x: T) { | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:21:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:22:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -38,25 +52,28 @@ LL | fn foo2(x: impl Trait) { | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:25:12 + --> $DIR/trait-with-missing-associated-type-restriction.rs:26:12 | LL | x.funk(3); | ^ expected associated type, found integer | = note: expected associated type `>::A` found type `{integer}` -help: a method is available that returns `>::A` +help: some methods are available that return `>::A` --> $DIR/trait-with-missing-associated-type-restriction.rs:8:5 | LL | fn func(&self) -> Self::A; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func` +LL | fn funk(&self, _: Self::A); +LL | fn funq(&self) -> Self::A {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::funq` help: consider constraining the associated type `>::A` to `{integer}` | LL | fn bar2>(x: T) { | ^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:26:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:27:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -69,7 +86,7 @@ LL | fn bar2>(x: T) { | ^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:30:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:31:9 | LL | fn baz>(x: T) { | - this type parameter @@ -80,13 +97,13 @@ LL | qux(x.func()) found type parameter `D` error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:34:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:35:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found `()` error[E0308]: mismatched types - --> $DIR/trait-with-missing-associated-type-restriction.rs:38:9 + --> $DIR/trait-with-missing-associated-type-restriction.rs:39:9 | LL | qux(x.func()) | ^^^^^^^^ expected `usize`, found associated type @@ -98,6 +115,6 @@ help: consider constraining the associated type `::A` to `usize` LL | fn ban(x: T) where T: Trait { | ^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0308`. From a23dd0d1e6ddfe6624f1c59e9aefcb59e419610d Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 13 May 2020 02:43:23 +0100 Subject: [PATCH 028/695] Replace fcntl-based file lock with flock WSL1 does not support `fcntl`-based lock and will always report success, therefore creating a race condition when multiple rustc processes are modifying shared data such as `search-index.js`. WSL1 does however support `flock`. `flock` is supported by all unix-like platforms. The only caveat is that Linux 2.6.11 or earlier does not support `flock` on NFS mounts, but as the minimum supported Linux version is 2.6.18, it is not an issue. Fixes #72157 --- src/librustc_data_structures/flock.rs | 67 ++++++++------------------- 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 2a0139fa90d5a..d6fc552e66149 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -12,13 +12,12 @@ use std::path::Path; cfg_if! { if #[cfg(unix)] { - use std::ffi::{CString, OsStr}; - use std::mem; use std::os::unix::prelude::*; + use std::fs::{File, OpenOptions}; #[derive(Debug)] pub struct Lock { - fd: libc::c_int, + _file: File, } impl Lock { @@ -27,63 +26,35 @@ cfg_if! { create: bool, exclusive: bool) -> io::Result { - let os: &OsStr = p.as_ref(); - let buf = CString::new(os.as_bytes()).unwrap(); - let open_flags = if create { - libc::O_RDWR | libc::O_CREAT + let file = OpenOptions::new() + .read(true) + .write(true) + .create(create) + .mode(libc::S_IRWXU as u32) + .open(p)?; + + let mut operation = if exclusive { + libc::LOCK_EX } else { - libc::O_RDWR - }; - - let fd = unsafe { - libc::open(buf.as_ptr(), open_flags, - libc::S_IRWXU as libc::c_int) + libc::LOCK_SH }; - - if fd < 0 { - return Err(io::Error::last_os_error()); + if !wait { + operation |= libc::LOCK_NB } - let lock_type = if exclusive { - libc::F_WRLCK - } else { - libc::F_RDLCK - }; - - let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = lock_type as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - flock.l_start = 0; - flock.l_len = 0; - - let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK }; - let ret = unsafe { - libc::fcntl(fd, cmd, &flock) - }; + let ret = unsafe { libc::flock(file.as_raw_fd(), operation) }; if ret == -1 { let err = io::Error::last_os_error(); - unsafe { libc::close(fd); } Err(err) } else { - Ok(Lock { fd }) + Ok(Lock { _file: file }) } } } - impl Drop for Lock { - fn drop(&mut self) { - let mut flock: libc::flock = unsafe { mem::zeroed() }; - flock.l_type = libc::F_UNLCK as libc::c_short; - flock.l_whence = libc::SEEK_SET as libc::c_short; - flock.l_start = 0; - flock.l_len = 0; - - unsafe { - libc::fcntl(self.fd, libc::F_SETLK, &flock); - libc::close(self.fd); - } - } - } + // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by + // `flock` is associated with the file descriptor and closing the file release it + // automatically. } else if #[cfg(windows)] { use std::mem; use std::os::windows::prelude::*; From b96a1a759528f3d43c54b4a18094ff6331d0d5fc Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Thu, 14 May 2020 00:08:00 +0200 Subject: [PATCH 029/695] remove broken link --- src/librustc_infer/infer/region_constraints/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 0c9f002a2a21d..3983e55717947 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -784,7 +784,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { ) } - /// See [`RegionInference::region_constraints_added_in_snapshot`]. + /// See `InferCtxt::region_constraints_added_in_snapshot`. pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> Option { self.undo_log .region_constraints_in_snapshot(mark) From 94e4b5ec316993200d75276b4e7c16a059bf3a57 Mon Sep 17 00:00:00 2001 From: Vardan Margaryan Date: Sun, 10 May 2020 00:08:41 +0300 Subject: [PATCH 030/695] Add the redundant_wildcard_enum_match lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/matches.rs | 48 +++++++++++++++++++ src/lintlist/mod.rs | 7 +++ .../match_wildcard_for_single_variants.fixed | 18 +++++++ .../ui/match_wildcard_for_single_variants.rs | 18 +++++++ .../match_wildcard_for_single_variants.stderr | 10 ++++ 7 files changed, 104 insertions(+) create mode 100644 tests/ui/match_wildcard_for_single_variants.fixed create mode 100644 tests/ui/match_wildcard_for_single_variants.rs create mode 100644 tests/ui/match_wildcard_for_single_variants.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index b25ef0493568d..d6298fec65a4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1439,6 +1439,7 @@ Released 2018-09-13 [`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms [`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm +[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0c4daeb731f9c..41046c18ed253 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -641,6 +641,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &matches::MATCH_OVERLAPPING_ARM, &matches::MATCH_REF_PATS, &matches::MATCH_SINGLE_BINDING, + &matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, &matches::MATCH_WILD_ERR_ARM, &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, &matches::SINGLE_MATCH, @@ -1147,6 +1148,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(¯o_use::MACRO_USE_IMPORTS), LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::MATCH_BOOL), + LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), LintId::of(&matches::SINGLE_MATCH_ELSE), LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 8f86535ef1e0f..42a6c4166194e 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -229,6 +229,40 @@ declare_clippy_lint! { "a wildcard enum match arm using `_`" } +declare_clippy_lint! { + /// **What it does:** Checks for wildcard enum matches for a single variant. + /// + /// **Why is this bad?** New enum variants added by library updates can be missed. + /// + /// **Known problems:** Suggested replacements may not use correct path to enum + /// if it's not present in the current scope. + /// + /// **Example:** + /// + /// ```rust + /// # enum Foo { A, B, C } + /// # let x = Foo::B; + /// match x { + /// Foo::A => {}, + /// Foo::B => {}, + /// _ => {}, + /// } + /// ``` + /// Use instead: + /// ```rust + /// # enum Foo { A, B, C } + /// # let x = Foo::B; + /// match x { + /// Foo::A => {}, + /// Foo::B => {}, + /// Foo::C => {}, + /// } + /// ``` + pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + pedantic, + "a wildcard enum match for a single variant" +} + declare_clippy_lint! { /// **What it does:** Checks for wildcard pattern used with others patterns in same match arm. /// @@ -356,6 +390,7 @@ impl_lint_pass!(Matches => [ MATCH_WILD_ERR_ARM, MATCH_AS_REF, WILDCARD_ENUM_MATCH_ARM, + MATCH_WILDCARD_FOR_SINGLE_VARIANTS, WILDCARD_IN_OR_PATTERNS, MATCH_SINGLE_BINDING, INFALLIBLE_DESTRUCTURING_MATCH, @@ -766,6 +801,19 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_ } } + if suggestion.len() == 1 { + // No need to check for non-exhaustive enum as in that case len would be greater than 1 + span_lint_and_sugg( + cx, + MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + wildcard_span, + message, + "try this", + suggestion[0].clone(), + Applicability::MachineApplicable, + ) + }; + span_lint_and_sugg( cx, WILDCARD_ENUM_MATCH_ARM, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index e1a6d4bdd31f6..250a7c09f7812 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1200,6 +1200,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "matches", }, + Lint { + name: "match_wildcard_for_single_variants", + group: "pedantic", + desc: "a wildcard enum match for a single variant", + deprecation: None, + module: "matches", + }, Lint { name: "maybe_infinite_iter", group: "pedantic", diff --git a/tests/ui/match_wildcard_for_single_variants.fixed b/tests/ui/match_wildcard_for_single_variants.fixed new file mode 100644 index 0000000000000..5f1a559f59143 --- /dev/null +++ b/tests/ui/match_wildcard_for_single_variants.fixed @@ -0,0 +1,18 @@ +// run-rustfix + +#![warn(clippy::match_wildcard_for_single_variants)] +#![allow(dead_code)] + +enum Foo { + A, + B, + C, +} + +fn main() { + match Foo::A { + Foo::A => {}, + Foo::B => {}, + Foo::C => {}, + } +} diff --git a/tests/ui/match_wildcard_for_single_variants.rs b/tests/ui/match_wildcard_for_single_variants.rs new file mode 100644 index 0000000000000..1159f9e722d71 --- /dev/null +++ b/tests/ui/match_wildcard_for_single_variants.rs @@ -0,0 +1,18 @@ +// run-rustfix + +#![warn(clippy::match_wildcard_for_single_variants)] +#![allow(dead_code)] + +enum Foo { + A, + B, + C, +} + +fn main() { + match Foo::A { + Foo::A => {}, + Foo::B => {}, + _ => {}, + } +} diff --git a/tests/ui/match_wildcard_for_single_variants.stderr b/tests/ui/match_wildcard_for_single_variants.stderr new file mode 100644 index 0000000000000..128dd4808bf7f --- /dev/null +++ b/tests/ui/match_wildcard_for_single_variants.stderr @@ -0,0 +1,10 @@ +error: wildcard match will miss any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:16:9 + | +LL | _ => {}, + | ^ help: try this: `Foo::C` + | + = note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings` + +error: aborting due to previous error + From 0ad9f7d651b52de4be6384c9b6dc893b389fd557 Mon Sep 17 00:00:00 2001 From: Vardan Margaryan Date: Sun, 10 May 2020 18:33:12 +0300 Subject: [PATCH 031/695] Fix trivial cases of new match_wildcard_for_single_variants lint --- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/misc_early.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/trivially_copy_pass_by_ref.rs | 2 +- tests/compile-test.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 3a52b1d3fc20b..4c604cd01075e 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatLiteral { let type_suffix = match lit_float_ty { LitFloatType::Suffixed(FloatTy::F32) => Some("f32"), LitFloatType::Suffixed(FloatTy::F64) => Some("f64"), - _ => None + LitFloatType::Unsuffixed => None }; let (is_whole, mut float_str) = match fty { FloatTy::F32 => { diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 62ee051624b48..552222eba2ee2 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -379,7 +379,7 @@ impl EarlyLintPass for MiscEarlyLints { let left_binding = match left { BindingMode::ByRef(Mutability::Mut) => "ref mut ", BindingMode::ByRef(Mutability::Not) => "ref ", - _ => "", + BindingMode::ByValue(..) => "", }; if let PatKind::Wild = right.kind { diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 4301157e16440..9cfc8d1913497 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn { return; } }, - _ => return, + FnKind::Closure(..) => return, } let mir = cx.tcx.optimized_mir(def_id); diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index a21818701dacc..c099c5533339c 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { } }, FnKind::Method(..) => (), - _ => return, + FnKind::Closure(..) => return, } // Exclude non-inherent impls diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 2c101220c5d68..8e0cb94317aff 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -161,7 +161,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TriviallyCopyPassByRef { } }, FnKind::Method(..) => (), - _ => return, + FnKind::Closure(..) => return, } // Exclude non-inherent impls diff --git a/tests/compile-test.rs b/tests/compile-test.rs index de2cf6d7873f8..a3df9d5ccbd16 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -44,7 +44,7 @@ fn third_party_crates() -> String { for entry in fs::read_dir(dep_dir).unwrap() { let path = match entry { Ok(entry) => entry.path(), - _ => continue, + Err(_) => continue, }; if let Some(name) = path.file_name().and_then(OsStr::to_str) { for dep in CRATES { From 494830797744c09d6de3b2b2452ab185d2204005 Mon Sep 17 00:00:00 2001 From: Vardan Margaryan Date: Sun, 10 May 2020 18:34:29 +0300 Subject: [PATCH 032/695] Fix cases of match_wildcard_for_single_variants lint when it is spanned on Option --- clippy_lints/src/consts.rs | 9 +++++---- clippy_lints/src/escape.rs | 4 ++-- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/loops.rs | 2 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/modulo_arithmetic.rs | 1 + clippy_lints/src/utils/mod.rs | 2 ++ 7 files changed, 13 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 81ddc8c0067c7..efb424bcb7bf9 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -139,6 +139,7 @@ impl Constant { .find(|r| r.map_or(true, |o| o != Ordering::Equal)) .unwrap_or_else(|| Some(l.len().cmp(&r.len()))), (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => { + #[allow(clippy::match_wildcard_for_single_variants)] match Self::partial_cmp(tcx, cmp_type, lv, rv) { Some(Equal) => Some(ls.cmp(rs)), x => x, @@ -354,14 +355,14 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { (Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec.get(index as usize) { Some(Constant::F32(x)) => Some(Constant::F32(*x)), Some(Constant::F64(x)) => Some(Constant::F64(*x)), - _ => None, + Some(_) | None => None, }, (Some(Constant::Vec(vec)), _) => { if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) { match vec.get(0) { Some(Constant::F32(x)) => Some(Constant::F32(*x)), Some(Constant::F64(x)) => Some(Constant::F64(*x)), - _ => None, + Some(_) | None => None, } } else { None @@ -532,7 +533,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { }) .collect::>>() .map(Constant::Vec), - _ => None, + Some(_) | None => None, }, ty::Float(FloatTy::F64) => match miri_to_const(len) { Some(Constant::Int(len)) => alloc @@ -546,7 +547,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { }) .collect::>>() .map(Constant::Vec), - _ => None, + Some(_) | None => None, }, // FIXME: implement other array type conversions. _ => None, diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 1ec60a0e6e67a..615afee33ef95 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -95,12 +95,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal { fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { match map.find(id) { Some(Node::Binding(_)) => (), - _ => return false, + Some(_) | None => return false, } match map.find(map.get_parent_node(id)) { Some(Node::Param(_)) => true, - _ => false, + Some(_) | None => false, } } diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 86317fb8bd5c4..8c61b2f86643d 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -410,7 +410,7 @@ fn is_zero(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { Some(Constant::Int(i)) => i == 0, Some(Constant::F32(f)) => f == 0.0, Some(Constant::F64(f)) => f == 0.0, - _ => false, + Some(_) | None => false, } } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 0bc6b70855ba6..39908bff5ed48 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2154,7 +2154,7 @@ fn is_loop_nested(cx: &LateContext<'_, '_>, loop_expr: &Expr<'_>, iter_expr: &Ex } }, Some(Node::Stmt(_)) => (), - _ => { + Some(_) | None => { return false; }, } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index e1d524c2231e4..38c2645d36e48 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -509,7 +509,7 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> boo Constant::F64(f) => *f == 0.0 || (*f).is_infinite(), _ => false, }), - _ => false, + Some(_) | None => false, } } diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 4ca90455bc4d1..3bb3eb15d9c26 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -37,6 +37,7 @@ struct OperandInfo { } fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option { + #[allow(clippy::match_wildcard_for_single_variants)] match constant(cx, cx.tables, operand) { Some((Constant::Int(v), _)) => match cx.tables.expr_ty(expr).kind { ty::Int(ity) => { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3b8ef18bfab86..7bc8be492e828 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -370,6 +370,7 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'_, 'tcx>, hir_id: HirId) -> O /// Checks whether this type implements `Drop`. pub fn has_drop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { + #[allow(clippy::match_wildcard_for_single_variants)] match ty.ty_adt_def() { Some(def) => def.has_dtor(cx.tcx), _ => false, @@ -444,6 +445,7 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_, '_>, def_id: DefId) -> bool { /// Gets the name of the item the expression is in, if available. pub fn get_item_name(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option { let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id); + #[allow(clippy::match_wildcard_for_single_variants)] match cx.tcx.hir().find(parent_id) { Some( Node::Item(Item { ident, .. }) From 749619cfe34be1ee591f3af748fbdd4d2f54d3f0 Mon Sep 17 00:00:00 2001 From: Vardan Margaryan Date: Thu, 14 May 2020 22:40:33 +0300 Subject: [PATCH 033/695] Apply suggestions from PR review --- clippy_lints/src/matches.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 42a6c4166194e..444f5bb0db6c9 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -810,7 +810,7 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_ message, "try this", suggestion[0].clone(), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ) }; @@ -821,7 +821,7 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_ message, "try this", suggestion.join(" | "), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ) } } From 1c59cd5f2110ff90a256f0948f05716403e84b85 Mon Sep 17 00:00:00 2001 From: Vardan Margaryan Date: Thu, 14 May 2020 22:41:05 +0300 Subject: [PATCH 034/695] Fix example code of wildcard_enum_match_arm lint --- clippy_lints/src/matches.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 444f5bb0db6c9..6fdb4cf9cd747 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -220,7 +220,7 @@ declare_clippy_lint! { /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); /// match x { - /// A => {}, + /// Foo::A(_) => {}, /// _ => {}, /// } /// ``` From 0148a7f26ce636ac22ac7797dcd7d292c59e8576 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 14 May 2020 07:46:43 -0500 Subject: [PATCH 035/695] InvalidUninitBytes: Track more info about access --- .../mir/interpret/allocation.rs | 37 ++++++++++++------ src/librustc_middle/mir/interpret/error.rs | 39 ++++++++++++++++--- src/librustc_middle/mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/validity.rs | 14 ++++--- 4 files changed, 67 insertions(+), 25 deletions(-) diff --git a/src/librustc_middle/mir/interpret/allocation.rs b/src/librustc_middle/mir/interpret/allocation.rs index 2b6cf224e2c1b..96195db0bacd2 100644 --- a/src/librustc_middle/mir/interpret/allocation.rs +++ b/src/librustc_middle/mir/interpret/allocation.rs @@ -11,6 +11,7 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ read_target_uint, write_target_uint, AllocId, InterpResult, Pointer, Scalar, ScalarMaybeUninit, + UninitBytesAccess, }; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] @@ -545,17 +546,23 @@ impl<'tcx, Tag: Copy, Extra> Allocation { impl<'tcx, Tag: Copy, Extra> Allocation { /// Checks whether the given range is entirely defined. /// - /// Returns `Ok(())` if it's defined. Otherwise returns the index of the byte - /// at which the first undefined access begins. - fn is_defined(&self, ptr: Pointer, size: Size) -> Result<(), Size> { + /// Returns `Ok(())` if it's defined. Otherwise returns the range of byte + /// indexes of the first contiguous undefined access. + fn is_defined(&self, ptr: Pointer, size: Size) -> Result<(), Range> { self.init_mask.is_range_initialized(ptr.offset, ptr.offset + size) // `Size` addition } - /// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes` - /// error which will report the first byte which is undefined. + /// Checks that a range of bytes is defined. If not, returns the `InvalidUndefBytes` + /// error which will report the first range of bytes which is undefined. fn check_defined(&self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { - self.is_defined(ptr, size) - .or_else(|idx| throw_ub!(InvalidUninitBytes(Some(Pointer::new(ptr.alloc_id, idx))))) + self.is_defined(ptr, size).or_else(|idx_range| { + throw_ub!(InvalidUninitBytes(Some(Box::new(UninitBytesAccess { + access_ptr: ptr.erase_tag(), + access_size: size, + uninit_ptr: Pointer::new(ptr.alloc_id, idx_range.start), + uninit_size: idx_range.end - idx_range.start, // `Size` subtraction + })))) + }) } pub fn mark_definedness(&mut self, ptr: Pointer, size: Size, new_state: bool) { @@ -758,19 +765,25 @@ impl InitMask { /// Checks whether the range `start..end` (end-exclusive) is entirely initialized. /// - /// Returns `Ok(())` if it's initialized. Otherwise returns the index of the byte - /// at which the first uninitialized access begins. + /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte + /// indexes for the first contiguous span of the uninitialized access. #[inline] - pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Size> { + pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Range> { if end > self.len { - return Err(self.len); + return Err(self.len..end); } // FIXME(oli-obk): optimize this for allocations larger than a block. let idx = (start.bytes()..end.bytes()).map(Size::from_bytes).find(|&i| !self.get(i)); match idx { - Some(idx) => Err(idx), + Some(idx) => { + let undef_end = (idx.bytes()..end.bytes()) + .map(Size::from_bytes) + .find(|&i| self.get(i)) + .unwrap_or(end); + Err(idx..undef_end) + } None => Ok(()), } } diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs index 06fe3793b2383..d32a147344992 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/src/librustc_middle/mir/interpret/error.rs @@ -6,7 +6,7 @@ use crate::ty::query::TyCtxtAt; use crate::ty::{self, layout, tls, FnSig, Ty}; use rustc_data_structures::sync::Lock; -use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorReported}; +use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::definitions::DefPathData; use rustc_macros::HashStable; @@ -327,6 +327,19 @@ impl fmt::Display for CheckInAllocMsg { } } +/// Details of an access to uninitialized bytes where it is not allowed. +#[derive(Debug)] +pub struct UninitBytesAccess { + /// Location of the original memory access. + pub access_ptr: Pointer, + /// Size of the original memory access. + pub access_size: Size, + /// Location of the first uninitialized byte that was accessed. + pub uninit_ptr: Pointer, + /// Number of consecutive uninitialized bytes that were accessed. + pub uninit_size: Size, +} + /// Error information for when the program caused Undefined Behavior. pub enum UndefinedBehaviorInfo<'tcx> { /// Free-form case. Only for errors that are never caught! @@ -384,7 +397,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. - InvalidUninitBytes(Option), + InvalidUninitBytes(Option>), /// Working with a local that is not currently live. DeadLocal, /// Data size is not equal to target size. @@ -455,10 +468,18 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { write!(f, "using {} as function pointer but it does not point to a function", p) } InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err), - InvalidUninitBytes(Some(p)) => write!( + InvalidUninitBytes(Some(access)) => write!( f, - "reading uninitialized memory at {}, but this operation requires initialized memory", - p + "reading {} byte{} of memory starting at {}, \ + but {} byte{} {} uninitialized starting at {}, \ + and this operation requires initialized memory", + access.access_size.bytes(), + pluralize!(access.access_size.bytes()), + access.access_ptr, + access.uninit_size.bytes(), + pluralize!(access.uninit_size.bytes()), + if access.uninit_size.bytes() != 1 { "are" } else { "is" }, + access.uninit_ptr, ), InvalidUninitBytes(None) => write!( f, @@ -556,6 +577,9 @@ impl dyn MachineStopType { } } +#[cfg(target_arch = "x86_64")] +static_assert_size!(InterpError<'_>, 40); + pub enum InterpError<'tcx> { /// The program caused undefined behavior. UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), @@ -604,7 +628,10 @@ impl InterpError<'_> { InterpError::MachineStop(b) => mem::size_of_val::(&**b) > 0, InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_)) - | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true, + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(_))) => { + true + } _ => false, } } diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs index 71adb2fa477ad..d9e52af89007c 100644 --- a/src/librustc_middle/mir/interpret/mod.rs +++ b/src/librustc_middle/mir/interpret/mod.rs @@ -119,7 +119,7 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, CheckInAllocMsg, ConstEvalErr, ConstEvalRawResult, ConstEvalResult, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, - ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, + ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit}; diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 7eb05ba2d2c54..6ce93f21021ca 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -366,7 +366,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let place = try_validation!( self.ecx.ref_to_mplace(value), self.path, - err_ub!(InvalidUninitBytes(..)) => { "uninitialized {}", kind }, + err_ub!(InvalidUninitBytes { .. }) => { "uninitialized {}", kind }, ); if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta, place.layout)?; @@ -514,7 +514,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let place = try_validation!( self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), self.path, - err_ub!(InvalidUninitBytes(..)) => { "uninitialized raw pointer" }, + err_ub!(InvalidUninitBytes { .. } ) => { "uninitialized raw pointer" }, ); if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta, place.layout)?; @@ -593,7 +593,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let value = try_validation!( value.not_undef(), self.path, - err_ub!(InvalidUninitBytes(..)) => { "{}", value } + err_ub!(InvalidUninitBytes { .. }) => { "{}", value } expected { "something {}", wrapping_range_format(valid_range, max_hi) }, ); let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) { @@ -804,12 +804,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // For some errors we might be able to provide extra information. // (This custom logic does not fit the `try_validation!` macro.) match err.kind { - err_ub!(InvalidUninitBytes(Some(ptr))) => { + err_ub!(InvalidUninitBytes(Some(access))) => { // Some byte was uninitialized, determine which // element that byte belongs to so we can // provide an index. - let i = usize::try_from(ptr.offset.bytes() / layout.size.bytes()) - .unwrap(); + let i = usize::try_from( + access.uninit_ptr.offset.bytes() / layout.size.bytes(), + ) + .unwrap(); self.path.push(PathElem::ArrayElem(i)); throw_validation_failure!(self.path, { "uninitialized bytes" }) From 10313a2631efa6a01dc86199d554ce5a7c1bb51a Mon Sep 17 00:00:00 2001 From: Vardan Margaryan Date: Fri, 15 May 2020 22:33:37 +0300 Subject: [PATCH 036/695] Revert "Fix cases of match_wildcard_for_single_variants lint when it is spanned on Option" This reverts commit 494830797744c09d6de3b2b2452ab185d2204005. --- clippy_lints/src/consts.rs | 9 ++++----- clippy_lints/src/escape.rs | 4 ++-- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/loops.rs | 2 +- clippy_lints/src/misc.rs | 2 +- clippy_lints/src/modulo_arithmetic.rs | 1 - clippy_lints/src/utils/mod.rs | 2 -- 7 files changed, 9 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index efb424bcb7bf9..81ddc8c0067c7 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -139,7 +139,6 @@ impl Constant { .find(|r| r.map_or(true, |o| o != Ordering::Equal)) .unwrap_or_else(|| Some(l.len().cmp(&r.len()))), (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => { - #[allow(clippy::match_wildcard_for_single_variants)] match Self::partial_cmp(tcx, cmp_type, lv, rv) { Some(Equal) => Some(ls.cmp(rs)), x => x, @@ -355,14 +354,14 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { (Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec.get(index as usize) { Some(Constant::F32(x)) => Some(Constant::F32(*x)), Some(Constant::F64(x)) => Some(Constant::F64(*x)), - Some(_) | None => None, + _ => None, }, (Some(Constant::Vec(vec)), _) => { if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) { match vec.get(0) { Some(Constant::F32(x)) => Some(Constant::F32(*x)), Some(Constant::F64(x)) => Some(Constant::F64(*x)), - Some(_) | None => None, + _ => None, } } else { None @@ -533,7 +532,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { }) .collect::>>() .map(Constant::Vec), - Some(_) | None => None, + _ => None, }, ty::Float(FloatTy::F64) => match miri_to_const(len) { Some(Constant::Int(len)) => alloc @@ -547,7 +546,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { }) .collect::>>() .map(Constant::Vec), - Some(_) | None => None, + _ => None, }, // FIXME: implement other array type conversions. _ => None, diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 615afee33ef95..1ec60a0e6e67a 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -95,12 +95,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal { fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { match map.find(id) { Some(Node::Binding(_)) => (), - Some(_) | None => return false, + _ => return false, } match map.find(map.get_parent_node(id)) { Some(Node::Param(_)) => true, - Some(_) | None => false, + _ => false, } } diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 8c61b2f86643d..86317fb8bd5c4 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -410,7 +410,7 @@ fn is_zero(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { Some(Constant::Int(i)) => i == 0, Some(Constant::F32(f)) => f == 0.0, Some(Constant::F64(f)) => f == 0.0, - Some(_) | None => false, + _ => false, } } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 39908bff5ed48..0bc6b70855ba6 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2154,7 +2154,7 @@ fn is_loop_nested(cx: &LateContext<'_, '_>, loop_expr: &Expr<'_>, iter_expr: &Ex } }, Some(Node::Stmt(_)) => (), - Some(_) | None => { + _ => { return false; }, } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 38c2645d36e48..e1d524c2231e4 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -509,7 +509,7 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> boo Constant::F64(f) => *f == 0.0 || (*f).is_infinite(), _ => false, }), - Some(_) | None => false, + _ => false, } } diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 3bb3eb15d9c26..4ca90455bc4d1 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -37,7 +37,6 @@ struct OperandInfo { } fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option { - #[allow(clippy::match_wildcard_for_single_variants)] match constant(cx, cx.tables, operand) { Some((Constant::Int(v), _)) => match cx.tables.expr_ty(expr).kind { ty::Int(ity) => { diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 7bc8be492e828..3b8ef18bfab86 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -370,7 +370,6 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'_, 'tcx>, hir_id: HirId) -> O /// Checks whether this type implements `Drop`. pub fn has_drop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { - #[allow(clippy::match_wildcard_for_single_variants)] match ty.ty_adt_def() { Some(def) => def.has_dtor(cx.tcx), _ => false, @@ -445,7 +444,6 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_, '_>, def_id: DefId) -> bool { /// Gets the name of the item the expression is in, if available. pub fn get_item_name(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option { let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id); - #[allow(clippy::match_wildcard_for_single_variants)] match cx.tcx.hir().find(parent_id) { Some( Node::Item(Item { ident, .. }) From 2620d2449da851171773f7bec1396af11babe278 Mon Sep 17 00:00:00 2001 From: Vardan Margaryan Date: Sat, 16 May 2020 00:06:52 +0300 Subject: [PATCH 037/695] Fix check for missing enum variants from match expressions TupleStruct matches are checked for exhaustiveness --- clippy_lints/src/matches.rs | 16 ++++++++++++++-- clippy_lints/src/utils/mod.rs | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 6fdb4cf9cd747..7d722820800c8 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -764,9 +764,21 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_ if let QPath::Resolved(_, p) = path { missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } - } else if let PatKind::TupleStruct(ref path, ..) = arm.pat.kind { + } else if let PatKind::TupleStruct(ref path, ref patterns, ..) = arm.pat.kind { if let QPath::Resolved(_, p) = path { - missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); + // Some simple checks for exhaustive patterns. + // There is a room for improvements to detect more cases, + // but it can be more expensive to do so. + let is_pattern_exhaustive = |pat: &&Pat<'_>| { + if let PatKind::Wild | PatKind::Binding(.., None) = pat.kind { + true + } else { + false + } + }; + if patterns.iter().all(is_pattern_exhaustive) { + missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); + } } } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3b8ef18bfab86..7545235e64670 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -372,7 +372,7 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'_, 'tcx>, hir_id: HirId) -> O pub fn has_drop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.ty_adt_def() { Some(def) => def.has_dtor(cx.tcx), - _ => false, + None => false, } } From d90625385e8ed0a9030e3ab2ea0990fce39c28bf Mon Sep 17 00:00:00 2001 From: Vardan Margaryan Date: Sat, 16 May 2020 00:19:30 +0300 Subject: [PATCH 038/695] Add more test cases for match_wildcard_for_single_variants --- .../match_wildcard_for_single_variants.fixed | 43 ++++++++++++++++++- .../ui/match_wildcard_for_single_variants.rs | 43 ++++++++++++++++++- .../match_wildcard_for_single_variants.stderr | 22 +++++++++- 3 files changed, 104 insertions(+), 4 deletions(-) diff --git a/tests/ui/match_wildcard_for_single_variants.fixed b/tests/ui/match_wildcard_for_single_variants.fixed index 5f1a559f59143..519200977a798 100644 --- a/tests/ui/match_wildcard_for_single_variants.fixed +++ b/tests/ui/match_wildcard_for_single_variants.fixed @@ -9,10 +9,51 @@ enum Foo { C, } +enum Color { + Red, + Green, + Blue, + Rgb(u8, u8, u8), +} + fn main() { - match Foo::A { + let f = Foo::A; + match f { Foo::A => {}, Foo::B => {}, Foo::C => {}, } + + let color = Color::Red; + + // check exhaustive bindings + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(_r, _g, _b) => {}, + Color::Blue => {}, + } + + // check exhaustive wild + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(..) => {}, + Color::Blue => {}, + } + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(_, _, _) => {}, + Color::Blue => {}, + } + + // shouldn't lint as there is one missing variant + // and one that isn't exhaustively covered + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(255, _, _) => {}, + _ => {}, + } } diff --git a/tests/ui/match_wildcard_for_single_variants.rs b/tests/ui/match_wildcard_for_single_variants.rs index 1159f9e722d71..1df917e085c71 100644 --- a/tests/ui/match_wildcard_for_single_variants.rs +++ b/tests/ui/match_wildcard_for_single_variants.rs @@ -9,10 +9,51 @@ enum Foo { C, } +enum Color { + Red, + Green, + Blue, + Rgb(u8, u8, u8), +} + fn main() { - match Foo::A { + let f = Foo::A; + match f { Foo::A => {}, Foo::B => {}, _ => {}, } + + let color = Color::Red; + + // check exhaustive bindings + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(_r, _g, _b) => {}, + _ => {}, + } + + // check exhaustive wild + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(..) => {}, + _ => {}, + } + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(_, _, _) => {}, + _ => {}, + } + + // shouldn't lint as there is one missing variant + // and one that isn't exhaustively covered + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(255, _, _) => {}, + _ => {}, + } } diff --git a/tests/ui/match_wildcard_for_single_variants.stderr b/tests/ui/match_wildcard_for_single_variants.stderr index 128dd4808bf7f..82790aa9e80bb 100644 --- a/tests/ui/match_wildcard_for_single_variants.stderr +++ b/tests/ui/match_wildcard_for_single_variants.stderr @@ -1,10 +1,28 @@ error: wildcard match will miss any future added variants - --> $DIR/match_wildcard_for_single_variants.rs:16:9 + --> $DIR/match_wildcard_for_single_variants.rs:24:9 | LL | _ => {}, | ^ help: try this: `Foo::C` | = note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings` -error: aborting due to previous error +error: wildcard match will miss any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:34:9 + | +LL | _ => {}, + | ^ help: try this: `Color::Blue` + +error: wildcard match will miss any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:42:9 + | +LL | _ => {}, + | ^ help: try this: `Color::Blue` + +error: wildcard match will miss any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:48:9 + | +LL | _ => {}, + | ^ help: try this: `Color::Blue` + +error: aborting due to 4 previous errors From 8fc62029114a917969a55a50f05c1688599a5c33 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Sat, 16 May 2020 04:57:40 +0200 Subject: [PATCH 039/695] Fix make sure out primary file comes first --- .../annotate_snippet_emitter_writer.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs index df5e43626aab9..5b47364e714e9 100644 --- a/src/librustc_errors/annotate_snippet_emitter_writer.rs +++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs @@ -104,14 +104,25 @@ impl AnnotateSnippetEmitterWriter { if let Some(source_map) = &self.source_map { // Make sure our primary file comes first let primary_lo = if let Some(ref primary_span) = msp.primary_span().as_ref() { - source_map.lookup_char_pos(primary_span.lo()) + if primary_span.is_dummy() { + // FIXME(#59346): Not sure when this is the case and what + // should be done if it happens + return; + } else { + source_map.lookup_char_pos(primary_span.lo()) + } } else { // FIXME(#59346): Not sure when this is the case and what // should be done if it happens return; }; - let annotated_files = + let mut annotated_files = FileWithAnnotatedLines::collect_annotations(msp, &self.source_map); + if let Ok(pos) = + annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) + { + annotated_files.swap(0, pos); + } // owned: line source, line index, annotations type Owned = (String, usize, Vec); let origin = primary_lo.file.name.to_string(); From 008d90a66a30bc8ff498f8ad47dea315c1853a75 Mon Sep 17 00:00:00 2001 From: csmoe Date: Sat, 16 May 2020 16:01:59 +0800 Subject: [PATCH 040/695] create error code E0754 --- src/librustc_error_codes/error_codes.rs | 1 + src/librustc_error_codes/error_codes/E0754.md | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/librustc_error_codes/error_codes/E0754.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index e01412bc21cfd..52d40fd0f2fa1 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -435,6 +435,7 @@ E0750: include_str!("./error_codes/E0750.md"), E0751: include_str!("./error_codes/E0751.md"), E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), +E0754: include_str!("./error_codes/E0754.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0754.md b/src/librustc_error_codes/error_codes/E0754.md new file mode 100644 index 0000000000000..e7cea98201003 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0754.md @@ -0,0 +1,29 @@ +`async fn`/`impl trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope. + +Erroneous code example: + +```compile_fail,E0754,edition2018 +struct S<'a>(&'a i32); + +impl<'a> S<'a> { + async fn new(i: &'a i32) -> Self { + S(&22) + } +} +``` + +To fix this error we need to spell out `Self` to `S<'a>`: + +```edition2018 +struct S<'a>(&'a i32); + +impl<'a> S<'a> { + async fn new(i: &'a i32) -> S<'a> { + S(&22) + } +} +``` + +This will be allowed at some point in the future, but the implementation is not yet complete. See the [issue-61949] for this limitation. + +[issue-61949]: https://github.com/rust-lang/rust/issues/61949 From 633e4aafe65cd424cf6c8076869df1b49a4e0ec4 Mon Sep 17 00:00:00 2001 From: csmoe Date: Sat, 16 May 2020 16:08:56 +0800 Subject: [PATCH 041/695] suggest on Self return type --- src/librustc_typeck/check/mod.rs | 67 +++++++++++++++++--------- src/test/ui/async-await/issue-69276.rs | 12 ----- 2 files changed, 43 insertions(+), 36 deletions(-) delete mode 100644 src/test/ui/async-await/issue-69276.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 57fdb03250e7a..0906c25baef09 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1639,51 +1639,56 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, struct ProhibitOpaqueVisitor<'tcx> { opaque_identity_ty: Ty<'tcx>, generics: &'tcx ty::Generics, + ty: Option>, }; impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); + self.ty = Some(t); if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) } } fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - return *index < self.generics.parent_count as u32; + let found_lifetime = *index < self.generics.parent_count as u32; + if !found_lifetime { + self.ty = None; + } + return found_lifetime; } r.super_visit_with(self) } } + let mut visitor = ProhibitOpaqueVisitor { + opaque_identity_ty: tcx.mk_opaque( + def_id.to_def_id(), + InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), + ), + generics: tcx.generics_of(def_id), + ty: None, + }; + debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor); + let prohibit_opaque = match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { - bounds, origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, .. - }) => { - let mut visitor = ProhibitOpaqueVisitor { - opaque_identity_ty: tcx.mk_opaque( - def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), - ), - generics: tcx.generics_of(def_id), - }; - debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor); - - for bound in bounds { - debug!("check_opaque_for_inheriting_lifetimes: {:?}", bound.trait_ref()); - } - tcx.predicates_of(def_id) - .predicates - .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor)) - } + }) => tcx + .predicates_of(def_id) + .predicates + .iter() + .any(|(predicate, _)| predicate.visit_with(&mut visitor)), _ => false, }; + debug!( + "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", + prohibit_opaque, visitor + ); - debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque); if prohibit_opaque { let is_async = match item.kind { ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { @@ -1693,14 +1698,28 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, _ => unreachable!(), }; - tcx.sess.span_err( + let mut err = struct_span_err!( + tcx.sess, span, - &format!( + E0754, "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ a parent scope", if is_async { "async fn" } else { "impl Trait" }, - ) ); + + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { + if snippet == "Self" { + if let Some(ty) = visitor.ty { + err.span_suggestion( + span, + "consider spelling out the type instead", + format!("{:?}", ty), + Applicability::MaybeIncorrect, + ); + } + } + } + err.emit(); } } diff --git a/src/test/ui/async-await/issue-69276.rs b/src/test/ui/async-await/issue-69276.rs deleted file mode 100644 index 224b76e2d903f..0000000000000 --- a/src/test/ui/async-await/issue-69276.rs +++ /dev/null @@ -1,12 +0,0 @@ -// edition:2018 - -struct S<'a>(&'a i32); - -impl<'a> S<'a> { - async fn new(i: &'a i32) -> Self { - //~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope - S(&22) - } -} - -fn main() {} From 27fc7e5e7a4fe9f21624541ab422f5bfa9ea8fa6 Mon Sep 17 00:00:00 2001 From: Hoe Hao Cheng Date: Sat, 16 May 2020 18:29:23 +0800 Subject: [PATCH 042/695] Implement PartialOrd and Ord for SocketAddr* --- src/libstd/net/addr.rs | 147 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 1 deletion(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index de6360cf020f5..267fb8544c324 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -1,3 +1,4 @@ +use crate::cmp::Ordering; use crate::convert::TryInto; use crate::fmt; use crate::hash; @@ -36,7 +37,7 @@ use crate::vec; /// assert_eq!(socket.port(), 8080); /// assert_eq!(socket.is_ipv4(), true); /// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SocketAddr { /// An IPv4 socket address. @@ -653,11 +654,115 @@ impl PartialEq for SocketAddrV6 { && self.inner.sin6_scope_id == other.inner.sin6_scope_id } } +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialEq for SocketAddr { + fn eq(&self, other: &SocketAddrV4) -> bool { + match self { + SocketAddr::V4(v4) => v4 == other, + SocketAddr::V6(_) => false, + } + } +} +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialEq for SocketAddr { + fn eq(&self, other: &SocketAddrV6) -> bool { + match self { + SocketAddr::V4(_) => false, + SocketAddr::V6(v6) => v6 == other, + } + } +} +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialEq for SocketAddrV4 { + fn eq(&self, other: &SocketAddr) -> bool { + match other { + SocketAddr::V4(v4) => self == v4, + SocketAddr::V6(_) => false, + } + } +} +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialEq for SocketAddrV6 { + fn eq(&self, other: &SocketAddr) -> bool { + match other { + SocketAddr::V4(_) => false, + SocketAddr::V6(v6) => self == v6, + } + } +} #[stable(feature = "rust1", since = "1.0.0")] impl Eq for SocketAddrV4 {} #[stable(feature = "rust1", since = "1.0.0")] impl Eq for SocketAddrV6 {} +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialOrd for SocketAddrV4 { + fn partial_cmp(&self, other: &SocketAddrV4) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialOrd for SocketAddrV4 { + fn partial_cmp(&self, other: &SocketAddr) -> Option { + match other { + SocketAddr::V4(v4) => self.partial_cmp(v4), + SocketAddr::V6(_) => Some(Ordering::Less), + } + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialOrd for SocketAddr { + fn partial_cmp(&self, other: &SocketAddrV4) -> Option { + match self { + SocketAddr::V4(v4) => v4.partial_cmp(other), + SocketAddr::V6(_) => Some(Ordering::Greater), + } + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialOrd for SocketAddrV6 { + fn partial_cmp(&self, other: &SocketAddrV6) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialOrd for SocketAddrV6 { + fn partial_cmp(&self, other: &SocketAddr) -> Option { + match other { + SocketAddr::V4(_) => Some(Ordering::Greater), + SocketAddr::V6(v6) => self.partial_cmp(v6), + } + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl PartialOrd for SocketAddr { + fn partial_cmp(&self, other: &SocketAddrV6) -> Option { + match self { + SocketAddr::V4(_) => Some(Ordering::Less), + SocketAddr::V6(v6) => v6.partial_cmp(other), + } + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl Ord for SocketAddrV4 { + fn cmp(&self, other: &SocketAddrV4) -> Ordering { + self.ip().cmp(other.ip()).then(self.port().cmp(&other.port())) + } +} + +#[stable(feature = "socketaddr_ordering", since = "1.45.0")] +impl Ord for SocketAddrV6 { + fn cmp(&self, other: &SocketAddrV6) -> Ordering { + self.ip().cmp(other.ip()).then(self.port().cmp(&other.port())) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl hash::Hash for SocketAddrV4 { fn hash(&self, s: &mut H) { @@ -1102,4 +1207,44 @@ mod tests { assert!(!v6.is_ipv4()); assert!(v6.is_ipv6()); } + + #[test] + fn compare() { + let v4_1 = "224.120.45.1:23456".parse::().unwrap(); + let v4_2 = "224.210.103.5:12345".parse::().unwrap(); + let v4_3 = "224.210.103.5:23456".parse::().unwrap(); + let v6_1 = "[2001:db8:f00::1002]:1234".parse::().unwrap(); + let v6_2 = "[2001:db8:f00::2001]:1234".parse::().unwrap(); + let v6_3 = "[2001:db8:f00::2001]:2345".parse::().unwrap(); + + // equality + assert_eq!(v4_1, SocketAddr::V4(v4_1)); + assert_eq!(v6_1, SocketAddr::V6(v6_1)); + assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); + assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); + assert!(v4_1 != SocketAddr::V6(v6_1)); + assert!(v6_1 != SocketAddr::V4(v4_1)); + assert!(v4_1 != v4_2); + assert!(v6_1 != v6_2); + + // compare different addresses + assert!(v4_1 < v4_2); + assert!(v4_1 < SocketAddr::V4(v4_2)); + assert!(SocketAddr::V4(v4_1) < v4_2); + assert!(SocketAddr::V4(v4_1) < SocketAddr::V4(v4_2)); + assert!(v6_1 < v6_2); + assert!(v6_1 < SocketAddr::V6(v6_2)); + assert!(SocketAddr::V6(v6_1) < v6_2); + assert!(SocketAddr::V6(v6_1) < SocketAddr::V6(v6_2)); + + // compare the same address with different ports + assert!(v4_2 < v4_3); + assert!(v4_2 < SocketAddr::V4(v4_3)); + assert!(SocketAddr::V4(v4_2) < v4_3); + assert!(SocketAddr::V4(v4_2) < SocketAddr::V4(v4_3)); + assert!(v6_2 < v6_3); + assert!(v6_2 < SocketAddr::V6(v6_3)); + assert!(SocketAddr::V6(v6_2) < v6_3); + assert!(SocketAddr::V6(v6_2) < SocketAddr::V6(v6_3)); + } } From e5b5f6f8a99253560096a5718fc7fc81daa23e02 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 17 May 2020 01:38:01 +0200 Subject: [PATCH 043/695] Better explain remotes in the sync process. --- CONTRIBUTING.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f7a6093837440..6697ff2f40d46 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -166,15 +166,18 @@ Clippy in the `rust-lang/rust` repository. For general information about `subtree`s in the Rust repository see [Rust's `CONTRIBUTING.md`][subtree]. -Here is a TL;DR version of the sync process: +Here is a TL;DR version of the sync process (all of the following commands have +to be run inside the `rust` directory): -1. Clone the [`rust-lang/rust`] repository (all of the following commands have - to be run inside the `rust` directory) +1. Clone the [`rust-lang/rust`] repository 2. Sync the changes to the rust-copy of Clippy to your Clippy fork: ```bash # Make sure to change `your-github-name` to your github name in the following command git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust ``` + _Note:_ This will directly push to the remote repository. You can also push + to your local copy by replacing the remote address with `/path/to/rust-clippy` + directory. 3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to accelerate the process ping the `@rust-lang/clippy` team in your PR and/or ~~annoy~~ ask them in the [Discord] channel.) @@ -185,6 +188,27 @@ Here is a TL;DR version of the sync process: ``` 5. Open a PR to [`rust-lang/rust`] +Also, you may want to define remotes, so you don't have to type out the remote +addresses on every sync. You can do this with the following commands (these +commands still have to be run inside the `rust` directory): + +```bash +# Set clippy-upstream remote for pulls +$ git remote add clippy-upstream https://github.com/rust-lang/rust-clippy +# Make sure to not push to the upstream repo +$ git remote set-url --push clippy-upstream DISABLED +# Set clippy-origin remote to your fork for pushes +$ git remote add clippy-origin git@github.com:your-github-name/rust-clippy +# Set a local remote +$ git remote add clippy-local /path/to/rust-clippy +``` + +You can then sync with the remote names from above, e.g.: + +```bash +$ git subtree push -P src/tools/clippy clippy-local sync-from-rust +``` + [subtree]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust From ba0d0c27df15b7a4d15d01eef3043ffb6cf65a8e Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Sun, 17 May 2020 08:21:24 +0200 Subject: [PATCH 044/695] Stabilization of weak-into-raw Stabilizes #60728. --- src/liballoc/rc.rs | 16 ++++------------ src/liballoc/sync.rs | 16 ++++------------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 307f6714f3230..f8db9095bec91 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -579,8 +579,6 @@ impl Rc { /// # Examples /// /// ``` - /// #![feature(weak_into_raw)] - /// /// use std::rc::Rc; /// /// let x = Rc::new("hello".to_owned()); @@ -589,7 +587,7 @@ impl Rc { /// assert_eq!(x_ptr, Rc::as_ptr(&y)); /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` - #[unstable(feature = "weak_into_raw", issue = "60728")] + #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(this.ptr); let fake_ptr = ptr as *mut T; @@ -1665,8 +1663,6 @@ impl Weak { /// # Examples /// /// ``` - /// #![feature(weak_into_raw)] - /// /// use std::rc::Rc; /// use std::ptr; /// @@ -1684,7 +1680,7 @@ impl Weak { /// ``` /// /// [`null`]: ../../std/ptr/fn.null.html - #[unstable(feature = "weak_into_raw", issue = "60728")] + #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let offset = data_offset_sized::(); let ptr = self.ptr.cast::().as_ptr().wrapping_offset(offset); @@ -1702,8 +1698,6 @@ impl Weak { /// # Examples /// /// ``` - /// #![feature(weak_into_raw)] - /// /// use std::rc::{Rc, Weak}; /// /// let strong = Rc::new("hello".to_owned()); @@ -1719,7 +1713,7 @@ impl Weak { /// /// [`from_raw`]: struct.Weak.html#method.from_raw /// [`as_ptr`]: struct.Weak.html#method.as_ptr - #[unstable(feature = "weak_into_raw", issue = "60728")] + #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { let result = self.as_ptr(); mem::forget(self); @@ -1746,8 +1740,6 @@ impl Weak { /// # Examples /// /// ``` - /// #![feature(weak_into_raw)] - /// /// use std::rc::{Rc, Weak}; /// /// let strong = Rc::new("hello".to_owned()); @@ -1772,7 +1764,7 @@ impl Weak { /// [`Weak`]: struct.Weak.html /// [`new`]: struct.Weak.html#method.new /// [`forget`]: ../../std/mem/fn.forget.html - #[unstable(feature = "weak_into_raw", issue = "60728")] + #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { if ptr.is_null() { Self::new() diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 2bcf763354247..ae4cf6cb5f442 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -578,8 +578,6 @@ impl Arc { /// # Examples /// /// ``` - /// #![feature(weak_into_raw)] - /// /// use std::sync::Arc; /// /// let x = Arc::new("hello".to_owned()); @@ -588,7 +586,7 @@ impl Arc { /// assert_eq!(x_ptr, Arc::as_ptr(&y)); /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` - #[unstable(feature = "weak_into_raw", issue = "60728")] + #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); let fake_ptr = ptr as *mut T; @@ -1446,8 +1444,6 @@ impl Weak { /// # Examples /// /// ``` - /// #![feature(weak_into_raw)] - /// /// use std::sync::Arc; /// use std::ptr; /// @@ -1465,7 +1461,7 @@ impl Weak { /// ``` /// /// [`null`]: ../../std/ptr/fn.null.html - #[unstable(feature = "weak_into_raw", issue = "60728")] + #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let offset = data_offset_sized::(); let ptr = self.ptr.cast::().as_ptr().wrapping_offset(offset); @@ -1483,8 +1479,6 @@ impl Weak { /// # Examples /// /// ``` - /// #![feature(weak_into_raw)] - /// /// use std::sync::{Arc, Weak}; /// /// let strong = Arc::new("hello".to_owned()); @@ -1500,7 +1494,7 @@ impl Weak { /// /// [`from_raw`]: struct.Weak.html#method.from_raw /// [`as_ptr`]: struct.Weak.html#method.as_ptr - #[unstable(feature = "weak_into_raw", issue = "60728")] + #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn into_raw(self) -> *const T { let result = self.as_ptr(); mem::forget(self); @@ -1528,8 +1522,6 @@ impl Weak { /// # Examples /// /// ``` - /// #![feature(weak_into_raw)] - /// /// use std::sync::{Arc, Weak}; /// /// let strong = Arc::new("hello".to_owned()); @@ -1554,7 +1546,7 @@ impl Weak { /// [`Weak`]: struct.Weak.html /// [`Arc`]: struct.Arc.html /// [`forget`]: ../../std/mem/fn.forget.html - #[unstable(feature = "weak_into_raw", issue = "60728")] + #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { if ptr.is_null() { Self::new() From f1d3086492db10deaa3268952792e93ad09ecec0 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 17 May 2020 17:36:26 +0200 Subject: [PATCH 045/695] Merge commit 'e214ea82ad0a751563acf67e1cd9279cf302db3a' into clippyup --- CHANGELOG.md | 44 ++- ...ondition.rs => blocks_in_if_conditions.rs} | 53 ++- clippy_lints/src/bytecount.rs | 2 +- clippy_lints/src/comparison_chain.rs | 17 +- clippy_lints/src/eq_op.rs | 2 +- clippy_lints/src/identity_op.rs | 22 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/lib.rs | 84 ++--- clippy_lints/src/loops.rs | 172 ++-------- clippy_lints/src/map_clone.rs | 2 +- clippy_lints/src/matches.rs | 2 +- .../src/methods/bind_instead_of_map.rs | 309 +++++++++++++++++ clippy_lints/src/methods/mod.rs | 323 ++++++------------ .../src/methods/option_map_unwrap_or.rs | 6 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/ranges.rs | 112 +++++- clippy_lints/src/returns.rs | 64 ++-- clippy_lints/src/types.rs | 4 +- clippy_lints/src/unwrap.rs | 12 +- ...ty_conversion.rs => useless_conversion.rs} | 30 +- clippy_lints/src/utils/diagnostics.rs | 28 +- clippy_lints/src/utils/usage.rs | 4 +- src/driver.rs | 222 ++++++------ src/lintlist/mod.rs | 130 +++---- ...n_some.fixed => bind_instead_of_map.fixed} | 4 +- ...nd_then_some.rs => bind_instead_of_map.rs} | 2 +- ...some.stderr => bind_instead_of_map.stderr} | 18 +- tests/ui/bind_instead_of_map_multipart.rs | 61 ++++ tests/ui/bind_instead_of_map_multipart.stderr | 73 ++++ ...on.fixed => blocks_in_if_conditions.fixed} | 7 +- ...ondition.rs => blocks_in_if_conditions.rs} | 7 +- ....stderr => blocks_in_if_conditions.stderr} | 10 +- ....rs => blocks_in_if_conditions_closure.rs} | 5 +- ...=> blocks_in_if_conditions_closure.stderr} | 6 +- tests/ui/comparison_chain.rs | 66 ++++ tests/ui/crashes/ice-5579.rs | 17 + tests/ui/expect.rs | 2 +- tests/ui/expect.stderr | 3 +- tests/ui/for_loop_fixable.fixed | 54 --- tests/ui/for_loop_fixable.rs | 54 --- tests/ui/for_loop_fixable.stderr | 88 +---- tests/ui/for_loop_unfixable.rs | 18 - tests/ui/for_loop_unfixable.stderr | 11 +- ..._result.rs => for_loops_over_fallibles.rs} | 10 +- ...stderr => for_loops_over_fallibles.stderr} | 19 +- tests/ui/identity_op.rs | 5 + tests/ui/identity_op.stderr | 20 +- tests/ui/implicit_saturating_sub.fixed | 4 +- tests/ui/implicit_saturating_sub.rs | 4 +- tests/ui/manual_memcpy.rs | 2 +- ...tion_map_unwrap_or.rs => map_unwrap_or.rs} | 23 +- ..._unwrap_or.stderr => map_unwrap_or.stderr} | 49 ++- tests/ui/option_map_or_none.fixed | 2 +- tests/ui/option_map_or_none.rs | 2 +- tests/ui/result_map_unwrap_or_else.rs | 23 -- tests/ui/result_map_unwrap_or_else.stderr | 27 -- tests/ui/reversed_empty_ranges_fixable.fixed | 24 ++ tests/ui/reversed_empty_ranges_fixable.rs | 24 ++ tests/ui/reversed_empty_ranges_fixable.stderr | 47 +++ .../reversed_empty_ranges_loops_fixable.fixed | 57 ++++ .../ui/reversed_empty_ranges_loops_fixable.rs | 57 ++++ ...reversed_empty_ranges_loops_fixable.stderr | 69 ++++ .../reversed_empty_ranges_loops_unfixable.rs | 11 + ...versed_empty_ranges_loops_unfixable.stderr | 16 + tests/ui/reversed_empty_ranges_unfixable.rs | 15 + .../ui/reversed_empty_ranges_unfixable.stderr | 34 ++ tests/ui/unused_unit.fixed | 21 +- tests/ui/unused_unit.rs | 18 +- tests/ui/unused_unit.stderr | 76 ++++- tests/ui/unwrap.rs | 2 +- tests/ui/unwrap.stderr | 3 +- ...version.fixed => useless_conversion.fixed} | 4 +- ...ty_conversion.rs => useless_conversion.rs} | 4 +- ...rsion.stderr => useless_conversion.stderr} | 46 +-- 74 files changed, 1770 insertions(+), 1102 deletions(-) rename clippy_lints/src/{block_in_if_condition.rs => blocks_in_if_conditions.rs} (78%) create mode 100644 clippy_lints/src/methods/bind_instead_of_map.rs rename clippy_lints/src/{identity_conversion.rs => useless_conversion.rs} (84%) rename tests/ui/{option_and_then_some.fixed => bind_instead_of_map.fixed} (90%) rename tests/ui/{option_and_then_some.rs => bind_instead_of_map.rs} (94%) rename tests/ui/{option_and_then_some.stderr => bind_instead_of_map.stderr} (50%) create mode 100644 tests/ui/bind_instead_of_map_multipart.rs create mode 100644 tests/ui/bind_instead_of_map_multipart.stderr rename tests/ui/{block_in_if_condition.fixed => blocks_in_if_conditions.fixed} (88%) rename tests/ui/{block_in_if_condition.rs => blocks_in_if_conditions.rs} (88%) rename tests/ui/{block_in_if_condition.stderr => blocks_in_if_conditions.stderr} (71%) rename tests/ui/{block_in_if_condition_closure.rs => blocks_in_if_conditions_closure.rs} (85%) rename tests/ui/{block_in_if_condition_closure.stderr => blocks_in_if_conditions_closure.stderr} (78%) create mode 100644 tests/ui/crashes/ice-5579.rs rename tests/ui/{for_loop_over_option_result.rs => for_loops_over_fallibles.rs} (81%) rename tests/ui/{for_loop_over_option_result.stderr => for_loops_over_fallibles.stderr} (81%) rename tests/ui/{option_map_unwrap_or.rs => map_unwrap_or.rs} (75%) rename tests/ui/{option_map_unwrap_or.stderr => map_unwrap_or.stderr} (70%) delete mode 100644 tests/ui/result_map_unwrap_or_else.rs delete mode 100644 tests/ui/result_map_unwrap_or_else.stderr create mode 100644 tests/ui/reversed_empty_ranges_fixable.fixed create mode 100644 tests/ui/reversed_empty_ranges_fixable.rs create mode 100644 tests/ui/reversed_empty_ranges_fixable.stderr create mode 100644 tests/ui/reversed_empty_ranges_loops_fixable.fixed create mode 100644 tests/ui/reversed_empty_ranges_loops_fixable.rs create mode 100644 tests/ui/reversed_empty_ranges_loops_fixable.stderr create mode 100644 tests/ui/reversed_empty_ranges_loops_unfixable.rs create mode 100644 tests/ui/reversed_empty_ranges_loops_unfixable.stderr create mode 100644 tests/ui/reversed_empty_ranges_unfixable.rs create mode 100644 tests/ui/reversed_empty_ranges_unfixable.stderr rename tests/ui/{identity_conversion.fixed => useless_conversion.fixed} (93%) rename tests/ui/{identity_conversion.rs => useless_conversion.rs} (94%) rename tests/ui/{identity_conversion.stderr => useless_conversion.stderr} (67%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8457d6ad05cf9..583c32ca9e032 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -198,7 +198,7 @@ Released 2020-03-12 ### Suggestion Improvements -* [`option_map_unwrap_or`] [#4634](https://github.com/rust-lang/rust-clippy/pull/4634) +* `option_map_unwrap_or` [#4634](https://github.com/rust-lang/rust-clippy/pull/4634) * [`wildcard_enum_match_arm`] [#4934](https://github.com/rust-lang/rust-clippy/pull/4934) * [`cognitive_complexity`] [#4935](https://github.com/rust-lang/rust-clippy/pull/4935) * [`decimal_literal_representation`] [#4956](https://github.com/rust-lang/rust-clippy/pull/4956) @@ -282,8 +282,8 @@ Released 2019-12-19 * [`panic`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657) * [`unreachable`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657) * [`todo`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657) - * [`option_expect_used`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657) - * [`result_expect_used`] [#4657](https://github.com/rust-lang/rust-clippy/pull/4657) + * `option_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657) + * `result_expect_used` [#4657](https://github.com/rust-lang/rust-clippy/pull/4657) * Move `redundant_clone` to perf group [#4509](https://github.com/rust-lang/rust-clippy/pull/4509) * Move `manual_mul_add` to nursery group [#4736](https://github.com/rust-lang/rust-clippy/pull/4736) * Expand `unit_cmp` to also work with `assert_eq!`, `debug_assert_eq!`, `assert_ne!` and `debug_assert_ne!` [#4613](https://github.com/rust-lang/rust-clippy/pull/4613) @@ -315,7 +315,7 @@ Released 2019-11-07 * [`missing_safety_doc`] [#4535](https://github.com/rust-lang/rust-clippy/pull/4535) * [`mem_replace_with_uninit`] [#4511](https://github.com/rust-lang/rust-clippy/pull/4511) * [`suspicious_map`] [#4394](https://github.com/rust-lang/rust-clippy/pull/4394) - * [`option_and_then_some`] [#4386](https://github.com/rust-lang/rust-clippy/pull/4386) + * `option_and_then_some` [#4386](https://github.com/rust-lang/rust-clippy/pull/4386) * [`manual_saturating_arithmetic`] [#4498](https://github.com/rust-lang/rust-clippy/pull/4498) * Deprecate `unused_collect` lint. This is fully covered by rustc's `#[must_use]` on `collect` [#4348](https://github.com/rust-lang/rust-clippy/pull/4348) * Move `type_repetition_in_bounds` to pedantic group [#4403](https://github.com/rust-lang/rust-clippy/pull/4403) @@ -395,7 +395,7 @@ Released 2019-08-15 * Fix false positive in [`useless_attribute`] [#4107](https://github.com/rust-lang/rust-clippy/pull/4107) * Fix incorrect suggestion for [`float_cmp`] [#4214](https://github.com/rust-lang/rust-clippy/pull/4214) * Add suggestions for [`print_with_newline`] and [`write_with_newline`] [#4136](https://github.com/rust-lang/rust-clippy/pull/4136) -* Improve suggestions for [`option_map_unwrap_or_else`] and [`result_map_unwrap_or_else`] [#4164](https://github.com/rust-lang/rust-clippy/pull/4164) +* Improve suggestions for `option_map_unwrap_or_else` and `result_map_unwrap_or_else` [#4164](https://github.com/rust-lang/rust-clippy/pull/4164) * Improve suggestions for [`non_ascii_literal`] [#4119](https://github.com/rust-lang/rust-clippy/pull/4119) * Improve diagnostics for [`let_and_return`] [#4137](https://github.com/rust-lang/rust-clippy/pull/4137) * Improve diagnostics for [`trivially_copy_pass_by_ref`] [#4071](https://github.com/rust-lang/rust-clippy/pull/4071) @@ -448,7 +448,7 @@ Released 2019-05-20 * Fix false positive in [`needless_range_loop`] pertaining to structs without a `.iter()` * Fix false positive in [`bool_comparison`] pertaining to non-bool types * Fix false positive in [`redundant_closure`] pertaining to differences in borrows -* Fix false positive in [`option_map_unwrap_or`] on non-copy types +* Fix false positive in `option_map_unwrap_or` on non-copy types * Fix false positives in [`missing_const_for_fn`] pertaining to macros and trait method impls * Fix false positive in [`needless_pass_by_value`] pertaining to procedural macros * Fix false positive in [`needless_continue`] pertaining to loop labels @@ -794,7 +794,7 @@ Released 2018-09-13 ## 0.0.169 * Rustup to *rustc 1.23.0-nightly (3b82e4c74 2017-11-05)* -* New lints: [`just_underscores_and_digits`], [`result_map_unwrap_or_else`], [`transmute_bytes_to_str`] +* New lints: [`just_underscores_and_digits`], `result_map_unwrap_or_else`, [`transmute_bytes_to_str`] ## 0.0.168 * Rustup to *rustc 1.23.0-nightly (f0fe716db 2017-10-30)* @@ -805,7 +805,7 @@ Released 2018-09-13 ## 0.0.166 * Rustup to *rustc 1.22.0-nightly (b7960878b 2017-10-18)* -* New lints: [`explicit_write`], [`identity_conversion`], [`implicit_hasher`], [`invalid_ref`], [`option_map_or_none`], +* New lints: [`explicit_write`], `identity_conversion`, [`implicit_hasher`], [`invalid_ref`], [`option_map_or_none`], [`range_minus_one`], [`range_plus_one`], [`transmute_int_to_bool`], [`transmute_int_to_char`], [`transmute_int_to_float`] @@ -1068,7 +1068,7 @@ Released 2018-09-13 ## 0.0.93 — 2016-10-03 * Rustup to *rustc 1.14.0-nightly (144af3e97 2016-10-02)* -* [`option_map_unwrap_or`] and [`option_map_unwrap_or_else`] are now +* `option_map_unwrap_or` and `option_map_unwrap_or_else` are now allowed by default. * New lint: [`explicit_into_iter_loop`] @@ -1087,8 +1087,8 @@ Released 2018-09-13 ## 0.0.88 — 2016-09-04 * Rustup to *rustc 1.13.0-nightly (70598e04f 2016-09-03)* * The following lints are not new but were only usable through the `clippy` - lint groups: [`filter_next`], [`for_loop_over_option`], - [`for_loop_over_result`] and [`match_overlapping_arm`]. You should now be + lint groups: [`filter_next`], `for_loop_over_option`, + `for_loop_over_result` and [`match_overlapping_arm`]. You should now be able to `#[allow/deny]` them individually and they are available directly through `cargo clippy`. @@ -1273,9 +1273,9 @@ Released 2018-09-13 [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask +[`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name -[`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr -[`block_in_if_condition_stmt`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt +[`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box @@ -1338,6 +1338,7 @@ Released 2018-09-13 [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision [`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit [`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call +[`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used [`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy [`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop [`explicit_deref_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_deref_methods @@ -1361,14 +1362,12 @@ Released 2018-09-13 [`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast [`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation [`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map -[`for_loop_over_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_option -[`for_loop_over_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_result +[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref [`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap -[`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op [`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex [`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching @@ -1431,6 +1430,7 @@ Released 2018-09-13 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten +[`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or [`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref [`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool [`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items @@ -1494,16 +1494,11 @@ Released 2018-09-13 [`not_unsafe_ptr_arg_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref [`ok_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#ok_expect [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref -[`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap -[`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used [`option_map_or_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_or_none [`option_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unit_fn -[`option_map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or -[`option_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or_else [`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option -[`option_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_unwrap_used [`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional @@ -1540,12 +1535,9 @@ Released 2018-09-13 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs -[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn -[`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else -[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used -[`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop +[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges [`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse @@ -1625,11 +1617,13 @@ Released 2018-09-13 [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit +[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used [`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug [`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self [`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding [`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref [`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute +[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion [`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format [`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq [`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/blocks_in_if_conditions.rs similarity index 78% rename from clippy_lints/src/block_in_if_condition.rs rename to clippy_lints/src/blocks_in_if_conditions.rs index 9e533eaa32c93..8fa9b05ca3297 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -8,43 +8,40 @@ use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Checks for `if` conditions that use blocks to contain an - /// expression. + /// **What it does:** Checks for `if` conditions that use blocks containing an + /// expression, statements or conditions that use closures with blocks. /// - /// **Why is this bad?** It isn't really Rust style, same as using parentheses - /// to contain expressions. + /// **Why is this bad?** Style, using blocks in the condition makes it hard to read. /// /// **Known problems:** None. /// - /// **Example:** + /// **Examples:** /// ```rust + /// // Bad /// if { true } { /* ... */ } + /// + /// // Good + /// if true { /* ... */ } /// ``` - pub BLOCK_IN_IF_CONDITION_EXPR, - style, - "braces that can be eliminated in conditions, e.g., `if { true } ...`" -} - -declare_clippy_lint! { - /// **What it does:** Checks for `if` conditions that use blocks containing - /// statements, or conditions that use closures with blocks. /// - /// **Why is this bad?** Using blocks in the condition makes it hard to read. + /// // or /// - /// **Known problems:** None. + /// ```rust + /// # fn somefunc() -> bool { true }; /// - /// **Example:** - /// ```rust,ignore - /// if { let x = somefunc(); x } {} - /// // or - /// if somefunc(|x| { x == 47 }) {} + /// // Bad + /// if { let x = somefunc(); x } { /* ... */ } + /// + /// // Good + /// let res = { let x = somefunc(); x }; + /// if res { /* ... */ } /// ``` - pub BLOCK_IN_IF_CONDITION_STMT, + pub BLOCKS_IN_IF_CONDITIONS, style, - "complex blocks in conditions, e.g., `if { let x = true; x } ...`" + "useless or complex blocks that can be eliminated in conditions" } -declare_lint_pass!(BlockInIfCondition => [BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT]); +declare_lint_pass!(BlocksInIfConditions => [BLOCKS_IN_IF_CONDITIONS]); struct ExVisitor<'a, 'tcx> { found_block: Option<&'tcx Expr<'tcx>>, @@ -72,9 +69,9 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition"; const COMPLEX_BLOCK_MESSAGE: &str = "in an `if` condition, avoid complex blocks or closures with blocks; \ - instead, move the block or closure higher and bind it with a `let`"; + instead, move the block or closure higher and bind it with a `let`"; -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlocksInIfConditions { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { if in_external_macro(cx.sess(), expr.span) { return; @@ -92,7 +89,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, - BLOCK_IN_IF_CONDITION_EXPR, + BLOCKS_IN_IF_CONDITIONS, cond.span, BRACED_EXPR_MESSAGE, "try", @@ -118,7 +115,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, - BLOCK_IN_IF_CONDITION_STMT, + BLOCKS_IN_IF_CONDITIONS, expr.span.with_hi(cond.span.hi()), COMPLEX_BLOCK_MESSAGE, "try", @@ -140,7 +137,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { let mut visitor = ExVisitor { found_block: None, cx }; walk_expr(&mut visitor, cond); if let Some(block) = visitor.found_block { - span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE); + span_lint(cx, BLOCKS_IN_IF_CONDITIONS, block.span, COMPLEX_BLOCK_MESSAGE); } } } diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 278d043732f49..90c00ad098ffe 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -3,7 +3,7 @@ use crate::utils::{ span_lint_and_sugg, walk_ptrs_ty, }; use if_chain::if_chain; -use rustc_ast::ast::{UintTy}; +use rustc_ast::ast::UintTy; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 96df3ffe3ce67..93e29edcaa58f 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -81,12 +81,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ComparisonChain { // Check that both sets of operands are equal let mut spanless_eq = SpanlessEq::new(cx); - if (!spanless_eq.eq_expr(lhs1, lhs2) || !spanless_eq.eq_expr(rhs1, rhs2)) - && (!spanless_eq.eq_expr(lhs1, rhs2) || !spanless_eq.eq_expr(rhs1, lhs2)) - { + let same_fixed_operands = spanless_eq.eq_expr(lhs1, lhs2) && spanless_eq.eq_expr(rhs1, rhs2); + let same_transposed_operands = spanless_eq.eq_expr(lhs1, rhs2) && spanless_eq.eq_expr(rhs1, lhs2); + + if !same_fixed_operands && !same_transposed_operands { return; } + // Check that if the operation is the same, either it's not `==` or the operands are transposed + if kind1.node == kind2.node { + if kind1.node == BinOpKind::Eq { + return; + } + if !same_transposed_operands { + return; + } + } + // Check that the type being compared implements `core::cmp::Ord` let ty = cx.tables.expr_ty(lhs1); let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[])); diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 098d47bdd40cb..4e1c1f131405f 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -115,7 +115,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { let rsnip = snippet(cx, r.span, "...").to_string(); multispan_sugg( diag, - "use the values directly".to_string(), + "use the values directly", vec![(left.span, lsnip), (right.span, rsnip)], ); }, diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 088e4ab1921fb..78e07d25f67c5 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -1,4 +1,5 @@ -use rustc_hir::{BinOpKind, Expr, ExprKind}; +use if_chain::if_chain; +use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -32,7 +33,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp { if e.span.from_expansion() { return; } - if let ExprKind::Binary(ref cmp, ref left, ref right) = e.kind { + if let ExprKind::Binary(cmp, ref left, ref right) = e.kind { + if is_allowed(cx, cmp, left, right) { + return; + } match cmp.node { BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => { check(cx, left, 0, e.span, right.span); @@ -54,6 +58,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp { } } +fn is_allowed(cx: &LateContext<'_, '_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool { + // `1 << 0` is a common pattern in bit manipulation code + if_chain! { + if let BinOpKind::Shl = cmp.node; + if let Some(Constant::Int(0)) = constant_simple(cx, cx.tables, right); + if let Some(Constant::Int(1)) = constant_simple(cx, cx.tables, left); + then { + return true; + } + } + + false +} + #[allow(clippy::cast_possible_wrap)] fn check(cx: &LateContext<'_, '_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) { if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) { diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 398a3103a0371..d7bf8a1476817 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -50,7 +50,7 @@ declare_clippy_lint! { /// }; /// ``` pub USELESS_LET_IF_SEQ, - style, + nursery, "unidiomatic `let mut` declaration followed by initialization in `if`" } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 51b5401da7d00..e0787ac0887e4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -180,7 +180,7 @@ mod attrs; mod await_holding_lock; mod bit_mask; mod blacklisted_name; -mod block_in_if_condition; +mod blocks_in_if_conditions; mod booleans; mod bytecount; mod cargo_common_metadata; @@ -221,7 +221,6 @@ mod formatting; mod functions; mod future_not_send; mod get_last_with_len; -mod identity_conversion; mod identity_op; mod if_let_mutex; mod if_let_some_result; @@ -324,6 +323,7 @@ mod unused_io_amount; mod unused_self; mod unwrap; mod use_self; +mod useless_conversion; mod vec; mod verbose_file_reads; mod wildcard_dependencies; @@ -507,8 +507,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &bit_mask::INEFFECTIVE_BIT_MASK, &bit_mask::VERBOSE_BIT_MASK, &blacklisted_name::BLACKLISTED_NAME, - &block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR, - &block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT, + &blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, &booleans::LOGIC_BUG, &booleans::NONMINIMAL_BOOL, &bytecount::NAIVE_BYTECOUNT, @@ -578,7 +577,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &functions::TOO_MANY_LINES, &future_not_send::FUTURE_NOT_SEND, &get_last_with_len::GET_LAST_WITH_LEN, - &identity_conversion::IDENTITY_CONVERSION, &identity_op::IDENTITY_OP, &if_let_mutex::IF_LET_MUTEX, &if_let_some_result::IF_LET_SOME_RESULT, @@ -616,15 +614,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &loops::EXPLICIT_INTO_ITER_LOOP, &loops::EXPLICIT_ITER_LOOP, &loops::FOR_KV_MAP, - &loops::FOR_LOOP_OVER_OPTION, - &loops::FOR_LOOP_OVER_RESULT, + &loops::FOR_LOOPS_OVER_FALLIBLES, &loops::ITER_NEXT_LOOP, &loops::MANUAL_MEMCPY, &loops::MUT_RANGE_BOUND, &loops::NEEDLESS_COLLECT, &loops::NEEDLESS_RANGE_LOOP, &loops::NEVER_LOOP, - &loops::REVERSE_RANGE_LOOP, &loops::WHILE_IMMUTABLE_CONDITION, &loops::WHILE_LET_LOOP, &loops::WHILE_LET_ON_ITERATOR, @@ -653,12 +649,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &mem_replace::MEM_REPLACE_OPTION_WITH_NONE, &mem_replace::MEM_REPLACE_WITH_DEFAULT, &mem_replace::MEM_REPLACE_WITH_UNINIT, + &methods::BIND_INSTEAD_OF_MAP, &methods::CHARS_LAST_CMP, &methods::CHARS_NEXT_CMP, &methods::CLONE_DOUBLE_REF, &methods::CLONE_ON_COPY, &methods::CLONE_ON_REF_PTR, &methods::EXPECT_FUN_CALL, + &methods::EXPECT_USED, &methods::FILETYPE_IS_FILE, &methods::FILTER_MAP, &methods::FILTER_MAP_NEXT, @@ -675,20 +673,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::ITER_SKIP_NEXT, &methods::MANUAL_SATURATING_ARITHMETIC, &methods::MAP_FLATTEN, + &methods::MAP_UNWRAP_OR, &methods::NEW_RET_NO_SELF, &methods::OK_EXPECT, - &methods::OPTION_AND_THEN_SOME, &methods::OPTION_AS_REF_DEREF, - &methods::OPTION_EXPECT_USED, &methods::OPTION_MAP_OR_NONE, - &methods::OPTION_MAP_UNWRAP_OR, - &methods::OPTION_MAP_UNWRAP_OR_ELSE, - &methods::OPTION_UNWRAP_USED, &methods::OR_FUN_CALL, - &methods::RESULT_EXPECT_USED, &methods::RESULT_MAP_OR_INTO_OPTION, - &methods::RESULT_MAP_UNWRAP_OR_ELSE, - &methods::RESULT_UNWRAP_USED, &methods::SEARCH_IS_SOME, &methods::SHOULD_IMPLEMENT_TRAIT, &methods::SINGLE_CHAR_PATTERN, @@ -699,6 +690,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::UNINIT_ASSUMED_INIT, &methods::UNNECESSARY_FILTER_MAP, &methods::UNNECESSARY_FOLD, + &methods::UNWRAP_USED, &methods::USELESS_ASREF, &methods::WRONG_PUB_SELF_CONVENTION, &methods::WRONG_SELF_CONVENTION, @@ -770,6 +762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &ranges::RANGE_MINUS_ONE, &ranges::RANGE_PLUS_ONE, &ranges::RANGE_ZIP_WITH_LEN, + &ranges::REVERSED_EMPTY_RANGES, &redundant_clone::REDUNDANT_CLONE, &redundant_field_names::REDUNDANT_FIELD_NAMES, &redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING, @@ -849,6 +842,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unwrap::PANICKING_UNWRAP, &unwrap::UNNECESSARY_UNWRAP, &use_self::USE_SELF, + &useless_conversion::USELESS_CONVERSION, &utils::internal_lints::CLIPPY_LINTS_INTERNAL, &utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS, &utils::internal_lints::COMPILER_LINT_FUNCTIONS, @@ -900,7 +894,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed); store.register_late_pass(|| box len_zero::LenZero); store.register_late_pass(|| box attrs::Attributes); - store.register_late_pass(|| box block_in_if_condition::BlockInIfCondition); + store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions); store.register_late_pass(|| box unicode::Unicode); store.register_late_pass(|| box strings::StringAdd); store.register_late_pass(|| box implicit_return::ImplicitReturn); @@ -986,7 +980,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box bytecount::ByteCount); store.register_late_pass(|| box infinite_iter::InfiniteIter); store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody); - store.register_late_pass(|| box identity_conversion::IdentityConversion::default()); + store.register_late_pass(|| box useless_conversion::UselessConversion::default()); store.register_late_pass(|| box types::ImplicitHasher); store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom); store.register_late_pass(|| box types::UnitArg); @@ -1090,12 +1084,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::WILDCARD_ENUM_MATCH_ARM), LintId::of(&mem_forget::MEM_FORGET), LintId::of(&methods::CLONE_ON_REF_PTR), + LintId::of(&methods::EXPECT_USED), LintId::of(&methods::FILETYPE_IS_FILE), LintId::of(&methods::GET_UNWRAP), - LintId::of(&methods::OPTION_EXPECT_USED), - LintId::of(&methods::OPTION_UNWRAP_USED), - LintId::of(&methods::RESULT_EXPECT_USED), - LintId::of(&methods::RESULT_UNWRAP_USED), + LintId::of(&methods::UNWRAP_USED), LintId::of(&methods::WRONG_PUB_SELF_CONVENTION), LintId::of(&misc::FLOAT_CMP_CONST), LintId::of(&misc_early::UNNEEDED_FIELD_PATTERN), @@ -1153,9 +1145,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::FIND_MAP), LintId::of(&methods::INEFFICIENT_TO_STRING), LintId::of(&methods::MAP_FLATTEN), - LintId::of(&methods::OPTION_MAP_UNWRAP_OR), - LintId::of(&methods::OPTION_MAP_UNWRAP_OR_ELSE), - LintId::of(&methods::RESULT_MAP_UNWRAP_OR_ELSE), + LintId::of(&methods::MAP_UNWRAP_OR), LintId::of(&misc::USED_UNDERSCORE_BINDING), LintId::of(&misc_early::UNSEPARATED_LITERAL_SUFFIX), LintId::of(&mut_mut::MUT_MUT), @@ -1209,8 +1199,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), - LintId::of(&block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR), - LintId::of(&block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT), + LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&booleans::LOGIC_BUG), LintId::of(&booleans::NONMINIMAL_BOOL), LintId::of(&bytecount::NAIVE_BYTECOUNT), @@ -1252,7 +1241,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(&functions::TOO_MANY_ARGUMENTS), LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), - LintId::of(&identity_conversion::IDENTITY_CONVERSION), LintId::of(&identity_op::IDENTITY_OP), LintId::of(&if_let_mutex::IF_LET_MUTEX), LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), @@ -1266,7 +1254,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), - LintId::of(&let_if_seq::USELESS_LET_IF_SEQ), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(&lifetimes::NEEDLESS_LIFETIMES), @@ -1275,15 +1262,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EMPTY_LOOP), LintId::of(&loops::EXPLICIT_COUNTER_LOOP), LintId::of(&loops::FOR_KV_MAP), - LintId::of(&loops::FOR_LOOP_OVER_OPTION), - LintId::of(&loops::FOR_LOOP_OVER_RESULT), + LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(&loops::ITER_NEXT_LOOP), LintId::of(&loops::MANUAL_MEMCPY), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::NEEDLESS_COLLECT), LintId::of(&loops::NEEDLESS_RANGE_LOOP), LintId::of(&loops::NEVER_LOOP), - LintId::of(&loops::REVERSE_RANGE_LOOP), LintId::of(&loops::WHILE_IMMUTABLE_CONDITION), LintId::of(&loops::WHILE_LET_LOOP), LintId::of(&loops::WHILE_LET_ON_ITERATOR), @@ -1305,6 +1290,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), + LintId::of(&methods::BIND_INSTEAD_OF_MAP), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::CLONE_DOUBLE_REF), @@ -1321,7 +1307,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), - LintId::of(&methods::OPTION_AND_THEN_SOME), LintId::of(&methods::OPTION_AS_REF_DEREF), LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::OR_FUN_CALL), @@ -1384,6 +1369,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&question_mark::QUESTION_MARK), LintId::of(&ranges::RANGE_MINUS_ONE), LintId::of(&ranges::RANGE_ZIP_WITH_LEN), + LintId::of(&ranges::REVERSED_EMPTY_RANGES), LintId::of(&redundant_clone::REDUNDANT_CLONE), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING), @@ -1440,6 +1426,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&unwrap::UNNECESSARY_UNWRAP), + LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&vec::USELESS_VEC), LintId::of(&write::PRINTLN_EMPTY_STRING), LintId::of(&write::PRINT_LITERAL), @@ -1456,8 +1443,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), - LintId::of(&block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR), - LintId::of(&block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT), + LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&collapsible_if::COLLAPSIBLE_IF), LintId::of(&comparison_chain::COMPARISON_CHAIN), LintId::of(&doc::MISSING_SAFETY_DOC), @@ -1476,7 +1462,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&inherent_to_string::INHERENT_TO_STRING), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), - LintId::of(&let_if_seq::USELESS_LET_IF_SEQ), LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), LintId::of(&loops::EMPTY_LOOP), LintId::of(&loops::FOR_KV_MAP), @@ -1561,7 +1546,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&format::USELESS_FORMAT), LintId::of(&functions::TOO_MANY_ARGUMENTS), LintId::of(&get_last_with_len::GET_LAST_WITH_LEN), - LintId::of(&identity_conversion::IDENTITY_CONVERSION), LintId::of(&identity_op::IDENTITY_OP), LintId::of(&int_plus_one::INT_PLUS_ONE), LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), @@ -1574,10 +1558,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::MATCH_AS_REF), LintId::of(&matches::MATCH_SINGLE_BINDING), LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), + LintId::of(&methods::BIND_INSTEAD_OF_MAP), LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), - LintId::of(&methods::OPTION_AND_THEN_SOME), LintId::of(&methods::OPTION_AS_REF_DEREF), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SKIP_WHILE_NEXT), @@ -1620,6 +1604,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unwrap::UNNECESSARY_UNWRAP), + LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), ]); @@ -1652,11 +1637,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), - LintId::of(&loops::FOR_LOOP_OVER_OPTION), - LintId::of(&loops::FOR_LOOP_OVER_RESULT), + LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(&loops::ITER_NEXT_LOOP), LintId::of(&loops::NEVER_LOOP), - LintId::of(&loops::REVERSE_RANGE_LOOP), LintId::of(&loops::WHILE_IMMUTABLE_CONDITION), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), @@ -1675,6 +1658,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(&ptr::MUT_FROM_REF), + LintId::of(&ranges::REVERSED_EMPTY_RANGES), LintId::of(®ex::INVALID_REGEX), LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), @@ -1728,6 +1712,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS), LintId::of(&future_not_send::FUTURE_NOT_SEND), + LintId::of(&let_if_seq::USELESS_LET_IF_SEQ), LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(&mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(&mutex_atomic::MUTEX_INTEGER), @@ -1785,6 +1770,10 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) { "unsafe_vector_initialization", "the replacement suggested by this lint had substantially different behavior", ); + store.register_removed( + "reverse_range_loop", + "this lint is now included in reversed_empty_ranges", + ); } /// Register renamed lints. @@ -1795,6 +1784,19 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) { ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default"); ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"); ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"); + ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map"); + ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"); + ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"); + ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"); + ls.register_renamed("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"); + ls.register_renamed("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"); + ls.register_renamed("clippy::option_unwrap_used", "clippy::unwrap_used"); + ls.register_renamed("clippy::result_unwrap_used", "clippy::unwrap_used"); + ls.register_renamed("clippy::option_expect_used", "clippy::expect_used"); + ls.register_renamed("clippy::result_expect_used", "clippy::expect_used"); + ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"); + ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"); + ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion"); } // only exists to let the dogfood integration test works. diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 2bbf4dba614b4..84e8a010738cf 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use crate::consts::constant; use crate::reexport::Name; use crate::utils::paths; use crate::utils::usage::{is_unused, mutated_variables}; @@ -8,7 +8,7 @@ use crate::utils::{ multispan_sugg, snippet, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, SpanlessEq, }; -use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg}; +use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sugg}; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -168,7 +168,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for `for` loops over `Option` values. + /// **What it does:** Checks for `for` loops over `Option` or `Result` values. /// /// **Why is this bad?** Readability. This is more clearly expressed as an `if /// let`. @@ -176,47 +176,38 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```ignore - /// for x in option { - /// .. + /// ```rust + /// # let opt = Some(1); + /// + /// // Bad + /// for x in opt { + /// // .. /// } - /// ``` /// - /// This should be - /// ```ignore - /// if let Some(x) = option { - /// .. + /// // Good + /// if let Some(x) = opt { + /// // .. /// } /// ``` - pub FOR_LOOP_OVER_OPTION, - correctness, - "for-looping over an `Option`, which is more clearly expressed as an `if let`" -} - -declare_clippy_lint! { - /// **What it does:** Checks for `for` loops over `Result` values. /// - /// **Why is this bad?** Readability. This is more clearly expressed as an `if - /// let`. + /// // or /// - /// **Known problems:** None. + /// ```rust + /// # let res: Result = Ok(1); /// - /// **Example:** - /// ```ignore - /// for x in result { - /// .. + /// // Bad + /// for x in &res { + /// // .. /// } - /// ``` /// - /// This should be - /// ```ignore - /// if let Ok(x) = result { - /// .. + /// // Good + /// if let Ok(x) = res { + /// // .. /// } /// ``` - pub FOR_LOOP_OVER_RESULT, + pub FOR_LOOPS_OVER_FALLIBLES, correctness, - "for-looping over a `Result`, which is more clearly expressed as an `if let`" + "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`" } declare_clippy_lint! { @@ -270,30 +261,6 @@ declare_clippy_lint! { "collecting an iterator when collect is not needed" } -declare_clippy_lint! { - /// **What it does:** Checks for loops over ranges `x..y` where both `x` and `y` - /// are constant and `x` is greater or equal to `y`, unless the range is - /// reversed or has a negative `.step_by(_)`. - /// - /// **Why is it bad?** Such loops will either be skipped or loop until - /// wrap-around (in debug code, this may `panic!()`). Both options are probably - /// not intended. - /// - /// **Known problems:** The lint cannot catch loops over dynamically defined - /// ranges. Doing this would require simulating all possible inputs and code - /// paths through the program, which would be complex and error-prone. - /// - /// **Example:** - /// ```ignore - /// for x in 5..10 - 5 { - /// .. - /// } // oops, stray `-` - /// ``` - pub REVERSE_RANGE_LOOP, - correctness, - "iteration over an empty range, such as `10..0` or `5..5`" -} - declare_clippy_lint! { /// **What it does:** Checks `for` loops over slices with an explicit counter /// and suggests the use of `.enumerate()`. @@ -459,11 +426,9 @@ declare_lint_pass!(Loops => [ EXPLICIT_ITER_LOOP, EXPLICIT_INTO_ITER_LOOP, ITER_NEXT_LOOP, - FOR_LOOP_OVER_RESULT, - FOR_LOOP_OVER_OPTION, + FOR_LOOPS_OVER_FALLIBLES, WHILE_LET_LOOP, NEEDLESS_COLLECT, - REVERSE_RANGE_LOOP, EXPLICIT_COUNTER_LOOP, EMPTY_LOOP, WHILE_LET_ON_ITERATOR, @@ -761,7 +726,6 @@ fn check_for_loop<'a, 'tcx>( expr: &'tcx Expr<'_>, ) { check_for_loop_range(cx, pat, arg, body, expr); - check_for_loop_reverse_range(cx, arg, expr); check_for_loop_arg(cx, pat, arg, expr); check_for_loop_explicit_counter(cx, pat, arg, body, expr); check_for_loop_over_map_kv(cx, pat, arg, body, expr); @@ -1170,7 +1134,7 @@ fn check_for_loop_range<'a, 'tcx>( |diag| { multispan_sugg( diag, - "consider using an iterator".to_string(), + "consider using an iterator", vec![ (pat.span, format!("({}, )", ident.name)), ( @@ -1199,7 +1163,7 @@ fn check_for_loop_range<'a, 'tcx>( |diag| { multispan_sugg( diag, - "consider using an iterator".to_string(), + "consider using an iterator", vec![(pat.span, "".to_string()), (arg.span, repl)], ); }, @@ -1248,78 +1212,6 @@ fn is_end_eq_array_len<'tcx>( false } -fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) { - // if this for loop is iterating over a two-sided range... - if let Some(higher::Range { - start: Some(start), - end: Some(end), - limits, - }) = higher::range(cx, arg) - { - // ...and both sides are compile-time constant integers... - if let Some((start_idx, _)) = constant(cx, cx.tables, start) { - if let Some((end_idx, _)) = constant(cx, cx.tables, end) { - // ...and the start index is greater than the end index, - // this loop will never run. This is often confusing for developers - // who think that this will iterate from the larger value to the - // smaller value. - let ty = cx.tables.expr_ty(start); - let (sup, eq) = match (start_idx, end_idx) { - (Constant::Int(start_idx), Constant::Int(end_idx)) => ( - match ty.kind { - ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity), - ty::Uint(_) => start_idx > end_idx, - _ => false, - }, - start_idx == end_idx, - ), - _ => (false, false), - }; - - if sup { - let start_snippet = snippet(cx, start.span, "_"); - let end_snippet = snippet(cx, end.span, "_"); - let dots = if limits == ast::RangeLimits::Closed { - "..=" - } else { - ".." - }; - - span_lint_and_then( - cx, - REVERSE_RANGE_LOOP, - expr.span, - "this range is empty so this for loop will never run", - |diag| { - diag.span_suggestion( - arg.span, - "consider using the following if you are attempting to iterate over this \ - range in reverse", - format!( - "({end}{dots}{start}).rev()", - end = end_snippet, - dots = dots, - start = start_snippet - ), - Applicability::MaybeIncorrect, - ); - }, - ); - } else if eq && limits != ast::RangeLimits::Closed { - // if they are equal, it's also problematic - this loop - // will never run. - span_lint( - cx, - REVERSE_RANGE_LOOP, - expr.span, - "this range is empty so this for loop will never run", - ); - } - } - } - } -} - fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) { let mut applicability = Applicability::MachineApplicable; let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); @@ -1381,7 +1273,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e ITER_NEXT_LOOP, expr.span, "you are iterating over `Iterator::next()` which is an Option; this will compile but is \ - probably not what you want", + probably not what you want", ); next_loop_linted = true; } @@ -1398,11 +1290,11 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) { if is_type_diagnostic_item(cx, ty, sym!(option_type)) { span_lint_and_help( cx, - FOR_LOOP_OVER_OPTION, + FOR_LOOPS_OVER_FALLIBLES, arg.span, &format!( "for loop over `{0}`, which is an `Option`. This is more readably written as an \ - `if let` statement.", + `if let` statement.", snippet(cx, arg.span, "_") ), None, @@ -1415,11 +1307,11 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) { } else if is_type_diagnostic_item(cx, ty, sym!(result_type)) { span_lint_and_help( cx, - FOR_LOOP_OVER_RESULT, + FOR_LOOPS_OVER_FALLIBLES, arg.span, &format!( "for loop over `{0}`, which is a `Result`. This is more readably written as an \ - `if let` statement.", + `if let` statement.", snippet(cx, arg.span, "_") ), None, @@ -1570,7 +1462,7 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( let map = sugg::Sugg::hir(cx, arg, "map"); multispan_sugg( diag, - "use the corresponding method".into(), + "use the corresponding method", vec![ (pat_span, snippet(cx, new_pat_span, kind).into_owned()), (arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl)), diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 0163b3f8dbc8e..d5adf6b0f0dcb 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -9,8 +9,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; use rustc_span::symbol::Ident; +use rustc_span::Span; declare_clippy_lint! { /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 8f86535ef1e0f..bbf14374a1f7f 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -820,7 +820,7 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_> span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| { if !expr.span.from_expansion() { - multispan_sugg(diag, msg.to_owned(), suggs); + multispan_sugg(diag, msg, suggs); } }); } diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs new file mode 100644 index 0000000000000..32e86637569ed --- /dev/null +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -0,0 +1,309 @@ +use super::{contains_return, BIND_INSTEAD_OF_MAP}; +use crate::utils::{ + in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, + snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; +use rustc_span::Span; + +pub(crate) struct OptionAndThenSome; +impl BindInsteadOfMap for OptionAndThenSome { + const TYPE_NAME: &'static str = "Option"; + const TYPE_QPATH: &'static [&'static str] = &paths::OPTION; + + const BAD_METHOD_NAME: &'static str = "and_then"; + const BAD_VARIANT_NAME: &'static str = "Some"; + const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::OPTION_SOME; + + const GOOD_METHOD_NAME: &'static str = "map"; +} + +pub(crate) struct ResultAndThenOk; +impl BindInsteadOfMap for ResultAndThenOk { + const TYPE_NAME: &'static str = "Result"; + const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; + + const BAD_METHOD_NAME: &'static str = "and_then"; + const BAD_VARIANT_NAME: &'static str = "Ok"; + const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::RESULT_OK; + + const GOOD_METHOD_NAME: &'static str = "map"; +} + +pub(crate) struct ResultOrElseErrInfo; +impl BindInsteadOfMap for ResultOrElseErrInfo { + const TYPE_NAME: &'static str = "Result"; + const TYPE_QPATH: &'static [&'static str] = &paths::RESULT; + + const BAD_METHOD_NAME: &'static str = "or_else"; + const BAD_VARIANT_NAME: &'static str = "Err"; + const BAD_VARIANT_QPATH: &'static [&'static str] = &paths::RESULT_ERR; + + const GOOD_METHOD_NAME: &'static str = "map_err"; +} + +pub(crate) trait BindInsteadOfMap { + const TYPE_NAME: &'static str; + const TYPE_QPATH: &'static [&'static str]; + + const BAD_METHOD_NAME: &'static str; + const BAD_VARIANT_NAME: &'static str; + const BAD_VARIANT_QPATH: &'static [&'static str]; + + const GOOD_METHOD_NAME: &'static str; + + fn no_op_msg() -> String { + format!( + "using `{}.{}({})`, which is a no-op", + Self::TYPE_NAME, + Self::BAD_METHOD_NAME, + Self::BAD_VARIANT_NAME + ) + } + + fn lint_msg() -> String { + format!( + "using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`", + Self::TYPE_NAME, + Self::BAD_METHOD_NAME, + Self::BAD_VARIANT_NAME, + Self::GOOD_METHOD_NAME + ) + } + + fn lint_closure_autofixable( + cx: &LateContext<'_, '_>, + expr: &hir::Expr<'_>, + args: &[hir::Expr<'_>], + closure_expr: &hir::Expr<'_>, + closure_args_span: Span, + ) -> bool { + if_chain! { + if let hir::ExprKind::Call(ref some_expr, ref some_args) = closure_expr.kind; + if let hir::ExprKind::Path(ref qpath) = some_expr.kind; + if match_qpath(qpath, Self::BAD_VARIANT_QPATH); + if some_args.len() == 1; + then { + let inner_expr = &some_args[0]; + + if contains_return(inner_expr) { + return false; + } + + 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 closure_args_snip = snippet(cx, closure_args_span, ".."); + let option_snip = snippet(cx, args[0].span, ".."); + let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip); + span_lint_and_sugg( + cx, + BIND_INSTEAD_OF_MAP, + expr.span, + Self::lint_msg().as_ref(), + "try this", + note, + Applicability::MachineApplicable, + ); + true + } else { + false + } + } + } + + fn lint_closure(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, closure_expr: &hir::Expr<'_>) { + let mut suggs = Vec::new(); + let can_sugg = find_all_ret_expressions(cx, closure_expr, |ret_expr| { + if_chain! { + if !in_macro(ret_expr.span); + if let hir::ExprKind::Call(ref func_path, ref args) = ret_expr.kind; + if let hir::ExprKind::Path(ref qpath) = func_path.kind; + if match_qpath(qpath, Self::BAD_VARIANT_QPATH); + if args.len() == 1; + if !contains_return(&args[0]); + then { + suggs.push((ret_expr.span, args[0].span.source_callsite())); + true + } else { + false + } + } + }); + + if can_sugg { + span_lint_and_then(cx, BIND_INSTEAD_OF_MAP, expr.span, Self::lint_msg().as_ref(), |diag| { + multispan_sugg_with_applicability( + diag, + "try this", + Applicability::MachineApplicable, + std::iter::once((*method_calls(expr, 1).2.get(0).unwrap(), Self::GOOD_METHOD_NAME.into())).chain( + suggs + .into_iter() + .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())), + ), + ) + }); + } + } + + /// Lint use of `_.and_then(|x| Some(y))` for `Option`s + fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + if !match_type(cx, cx.tables.expr_ty(&args[0]), Self::TYPE_QPATH) { + return; + } + + match args[1].kind { + hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => { + let closure_body = cx.tcx.hir().body(body_id); + let closure_expr = remove_blocks(&closure_body.value); + + if !Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) { + Self::lint_closure(cx, expr, closure_expr); + } + }, + // `_.and_then(Some)` case, which is no-op. + hir::ExprKind::Path(ref qpath) if match_qpath(qpath, Self::BAD_VARIANT_QPATH) => { + span_lint_and_sugg( + cx, + BIND_INSTEAD_OF_MAP, + expr.span, + Self::no_op_msg().as_ref(), + "use the expression directly", + snippet(cx, args[0].span, "..").into(), + Applicability::MachineApplicable, + ); + }, + _ => {}, + } + } +} + +/// returns `true` if expr contains match expr desugared from try +fn contains_try(expr: &hir::Expr<'_>) -> bool { + struct TryFinder { + found: bool, + } + + impl<'hir> intravisit::Visitor<'hir> for TryFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { + if self.found { + return; + } + match expr.kind { + hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, + _ => intravisit::walk_expr(self, expr), + } + } + } + + let mut visitor = TryFinder { found: false }; + visitor.visit_expr(expr); + visitor.found +} + +fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_, '_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool +where + F: FnMut(&'hir hir::Expr<'hir>) -> bool, +{ + struct RetFinder { + in_stmt: bool, + failed: bool, + cb: F, + } + + struct WithStmtGuarg<'a, F> { + val: &'a mut RetFinder, + prev_in_stmt: bool, + } + + impl RetFinder { + fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { + let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); + WithStmtGuarg { + val: self, + prev_in_stmt, + } + } + } + + impl std::ops::Deref for WithStmtGuarg<'_, F> { + type Target = RetFinder; + + fn deref(&self) -> &Self::Target { + self.val + } + } + + impl std::ops::DerefMut for WithStmtGuarg<'_, F> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.val + } + } + + impl Drop for WithStmtGuarg<'_, F> { + fn drop(&mut self) { + self.val.in_stmt = self.prev_in_stmt; + } + } + + impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { + if self.failed { + return; + } + if self.in_stmt { + match expr.kind { + hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), + _ => intravisit::walk_expr(self, expr), + } + } else { + match expr.kind { + hir::ExprKind::Match(cond, arms, _) => { + self.inside_stmt(true).visit_expr(cond); + for arm in arms { + self.visit_expr(arm.body); + } + }, + hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), + hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), + _ => self.failed |= !(self.cb)(expr), + } + } + } + } + + !contains_try(expr) && { + let mut ret_finder = RetFinder { + in_stmt: false, + failed: false, + cb: callback, + }; + ret_finder.visit_expr(expr); + !ret_finder.failed + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3676dc5b09d21..626427c15ecf5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,3 +1,4 @@ +mod bind_instead_of_map; mod inefficient_to_string; mod manual_saturating_arithmetic; mod option_map_unwrap_or; @@ -7,6 +8,7 @@ use std::borrow::Cow; use std::fmt; use std::iter; +use bind_instead_of_map::BindInsteadOfMap; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; @@ -33,40 +35,15 @@ use crate::utils::{ }; declare_clippy_lint! { - /// **What it does:** Checks for `.unwrap()` calls on `Option`s. + /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s. /// - /// **Why is this bad?** Usually it is better to handle the `None` case, or to - /// at least call `.expect(_)` with a more helpful message. Still, for a lot of + /// **Why is this bad?** It is better to handle the `None` or `Err` case, + /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is /// `Allow` by default. /// - /// **Known problems:** None. - /// - /// **Example:** - /// - /// Using unwrap on an `Option`: - /// - /// ```rust - /// let opt = Some(1); - /// opt.unwrap(); - /// ``` - /// - /// Better: - /// - /// ```rust - /// let opt = Some(1); - /// opt.expect("more helpful message"); - /// ``` - pub OPTION_UNWRAP_USED, - restriction, - "using `Option.unwrap()`, which should at least get a better message using `expect()`" -} - -declare_clippy_lint! { - /// **What it does:** Checks for `.unwrap()` calls on `Result`s. - /// - /// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err` - /// values. Normally, you want to implement more sophisticated error handling, + /// `result.unwrap()` will let the thread panic on `Err` values. + /// Normally, you want to implement more sophisticated error handling, /// and propagate errors upwards with `?` operator. /// /// Even if you want to panic on errors, not all `Error`s implement good @@ -75,81 +52,73 @@ declare_clippy_lint! { /// /// **Known problems:** None. /// - /// **Example:** - /// Using unwrap on an `Result`: - /// + /// **Examples:** /// ```rust - /// let res: Result = Ok(1); - /// res.unwrap(); + /// # let opt = Some(1); + /// + /// // Bad + /// opt.unwrap(); + /// + /// // Good + /// opt.expect("more helpful message"); /// ``` /// - /// Better: + /// // or /// /// ```rust - /// let res: Result = Ok(1); + /// # let res: Result = Ok(1); + /// + /// // Bad + /// res.unwrap(); + /// + /// // Good /// res.expect("more helpful message"); /// ``` - pub RESULT_UNWRAP_USED, + pub UNWRAP_USED, restriction, - "using `Result.unwrap()`, which might be better handled" + "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`" } declare_clippy_lint! { - /// **What it does:** Checks for `.expect()` calls on `Option`s. + /// **What it does:** Checks for `.expect()` calls on `Option`s and `Result`s. /// - /// **Why is this bad?** Usually it is better to handle the `None` case. Still, - /// for a lot of quick-and-dirty code, `expect` is a good choice, which is why - /// this lint is `Allow` by default. + /// **Why is this bad?** Usually it is better to handle the `None` or `Err` case. + /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why + /// this lint is `Allow` by default. /// - /// **Known problems:** None. + /// `result.expect()` will let the thread panic on `Err` + /// values. Normally, you want to implement more sophisticated error handling, + /// and propagate errors upwards with `?` operator. /// - /// **Example:** + /// **Known problems:** None. /// - /// Using expect on an `Option`: + /// **Examples:** + /// ```rust,ignore + /// # let opt = Some(1); /// - /// ```rust - /// let opt = Some(1); + /// // Bad /// opt.expect("one"); - /// ``` /// - /// Better: - /// - /// ```rust,ignore + /// // Good /// let opt = Some(1); /// opt?; /// ``` - pub OPTION_EXPECT_USED, - restriction, - "using `Option.expect()`, which might be better handled" -} - -declare_clippy_lint! { - /// **What it does:** Checks for `.expect()` calls on `Result`s. /// - /// **Why is this bad?** `result.expect()` will let the thread panic on `Err` - /// values. Normally, you want to implement more sophisticated error handling, - /// and propagate errors upwards with `?` operator. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// Using expect on an `Result`: + /// // or /// /// ```rust - /// let res: Result = Ok(1); - /// res.expect("one"); - /// ``` + /// # let res: Result = Ok(1); /// - /// Better: + /// // Bad + /// res.expect("one"); /// - /// ```rust - /// let res: Result = Ok(1); + /// // Good /// res?; /// # Ok::<(), ()>(()) /// ``` - pub RESULT_EXPECT_USED, + pub EXPECT_USED, restriction, - "using `Result.expect()`, which might be better handled" + "using `.expect()` on `Result` or `Option`, which might be better handled" } declare_clippy_lint! { @@ -257,59 +226,40 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).unwrap_or(_)`. + /// **What it does:** Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or + /// `result.map(_).unwrap_or_else(_)`. /// - /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.map_or(_, _)`. + /// **Why is this bad?** Readability, these can be written more concisely (resp.) as + /// `option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`. /// /// **Known problems:** The order of the arguments is not in execution order /// - /// **Example:** + /// **Examples:** /// ```rust /// # let x = Some(1); - /// x.map(|a| a + 1).unwrap_or(0); - /// ``` - pub OPTION_MAP_UNWRAP_OR, - pedantic, - "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`" -} - -declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).unwrap_or_else(_)`. - /// - /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.map_or_else(_, _)`. /// - /// **Known problems:** The order of the arguments is not in execution order. + /// // Bad + /// x.map(|a| a + 1).unwrap_or(0); /// - /// **Example:** - /// ```rust - /// # let x = Some(1); - /// # fn some_function() -> usize { 1 } - /// x.map(|a| a + 1).unwrap_or_else(some_function); + /// // Good + /// x.map_or(0, |a| a + 1); /// ``` - pub OPTION_MAP_UNWRAP_OR_ELSE, - pedantic, - "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`" -} - -declare_clippy_lint! { - /// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`. /// - /// **Why is this bad?** Readability, this can be written more concisely as - /// `result.map_or_else(_, _)`. + /// // or /// - /// **Known problems:** None. - /// - /// **Example:** /// ```rust /// # let x: Result = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } + /// + /// // Bad /// x.map(|a| a + 1).unwrap_or_else(some_function); + /// + /// // Good + /// x.map_or_else(some_function, |a| a + 1); /// ``` - pub RESULT_MAP_UNWRAP_OR_ELSE, + pub MAP_UNWRAP_OR, pedantic, - "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.map_or_else(g, f)`" + "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`" } declare_clippy_lint! { @@ -358,27 +308,34 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`. + /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or + /// `_.or_else(|x| Err(y))`. /// /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.map(|x| y)`. + /// `_.map(|x| y)` or `_.map_err(|x| y)`. /// /// **Known problems:** None /// /// **Example:** /// /// ```rust - /// let x = Some("foo"); - /// let _ = x.and_then(|s| Some(s.len())); + /// # fn opt() -> Option<&'static str> { Some("42") } + /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } + /// let _ = opt().and_then(|s| Some(s.len())); + /// let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) }); + /// let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) }); /// ``` /// /// The correct use would be: /// /// ```rust - /// let x = Some("foo"); - /// let _ = x.map(|s| s.len()); + /// # fn opt() -> Option<&'static str> { Some("42") } + /// # fn res() -> Result<&'static str, &'static str> { Ok("42") } + /// let _ = opt().map(|s| s.len()); + /// let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 }); + /// let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 }); /// ``` - pub OPTION_AND_THEN_SOME, + pub BIND_INSTEAD_OF_MAP, complexity, "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`" } @@ -1286,20 +1243,16 @@ declare_clippy_lint! { } declare_lint_pass!(Methods => [ - OPTION_UNWRAP_USED, - RESULT_UNWRAP_USED, - OPTION_EXPECT_USED, - RESULT_EXPECT_USED, + UNWRAP_USED, + EXPECT_USED, SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, WRONG_PUB_SELF_CONVENTION, OK_EXPECT, - OPTION_MAP_UNWRAP_OR, - OPTION_MAP_UNWRAP_OR_ELSE, - RESULT_MAP_UNWRAP_OR_ELSE, + MAP_UNWRAP_OR, RESULT_MAP_OR_INTO_OPTION, OPTION_MAP_OR_NONE, - OPTION_AND_THEN_SOME, + BIND_INSTEAD_OF_MAP, OR_FUN_CALL, EXPECT_FUN_CALL, CHARS_NEXT_CMP, @@ -1358,7 +1311,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["unwrap_or", "map"] => option_map_unwrap_or::lint(cx, expr, arg_lists[1], arg_lists[0], method_spans[1]), ["unwrap_or_else", "map"] => lint_map_unwrap_or_else(cx, expr, arg_lists[1], arg_lists[0]), ["map_or", ..] => lint_map_or_none(cx, expr, arg_lists[0]), - ["and_then", ..] => lint_option_and_then_some(cx, expr, arg_lists[0]), + ["and_then", ..] => { + bind_instead_of_map::OptionAndThenSome::lint(cx, expr, arg_lists[0]); + bind_instead_of_map::ResultAndThenOk::lint(cx, expr, arg_lists[0]); + }, + ["or_else", ..] => { + bind_instead_of_map::ResultOrElseErrInfo::lint(cx, expr, arg_lists[0]); + }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), @@ -1503,9 +1462,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { cx, lint, first_arg.pat.span, - &format!( - "methods called `{}` usually take {}; consider choosing a less \ - ambiguous name", + &format!("methods called `{}` usually take {}; consider choosing a less ambiguous name", conv, &self_kinds .iter() @@ -1678,7 +1635,7 @@ fn lint_or_fun_call<'a, 'tcx>( let self_ty = cx.tables.expr_ty(self_expr); if let Some(&(_, fn_has_arguments, poss, suffix)) = - know_types.iter().find(|&&i| match_type(cx, self_ty, i.0)); + know_types.iter().find(|&&i| match_type(cx, self_ty, i.0)); if poss.contains(&name); @@ -1931,7 +1888,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir: CLONE_DOUBLE_REF, expr.span, "using `clone` on a double-reference; \ - this will copy the reference instead of cloning the inner type", + this will copy the reference instead of cloning the inner type", |diag| { if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { let mut ty = innermost; @@ -2121,7 +2078,7 @@ fn lint_iter_cloned_collect<'a, 'tcx>( ITER_CLONED_COLLECT, to_replace, "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \ - more readable", + more readable", "try", ".to_vec()".to_string(), Applicability::MachineApplicable, @@ -2420,9 +2377,9 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hi let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0])); let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { - Some((OPTION_UNWRAP_USED, "an Option", "None")) + Some((UNWRAP_USED, "an Option", "None")) } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) { - Some((RESULT_UNWRAP_USED, "a Result", "Err")) + Some((UNWRAP_USED, "a Result", "Err")) } else { None }; @@ -2436,7 +2393,7 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hi None, &format!( "if you don't want to handle the `{}` case gracefully, consider \ - using `expect()` to provide a better panic message", + using `expect()` to provide a better panic message", none_value, ), ); @@ -2448,9 +2405,9 @@ fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hi let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&expect_args[0])); let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { - Some((OPTION_EXPECT_USED, "an Option", "None")) + Some((EXPECT_USED, "an Option", "None")) } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) { - Some((RESULT_EXPECT_USED, "a Result", "Err")) + Some((EXPECT_USED, "a Result", "Err")) } else { None }; @@ -2494,7 +2451,7 @@ fn lint_map_flatten<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr< // lint if caller of `.map().flatten()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { let msg = "called `map(..).flatten()` on an `Iterator`. \ - This is more succinctly expressed by calling `.flat_map(..)`"; + This is more succinctly expressed by calling `.flat_map(..)`"; let self_snippet = snippet(cx, map_args[0].span, ".."); let func_snippet = snippet(cx, map_args[1].span, ".."); let hint = format!("{0}.flat_map({1})", self_snippet, func_snippet); @@ -2555,10 +2512,10 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( // lint message let msg = if is_option { "called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling \ - `map_or_else(g, f)` instead" + `map_or_else(g, f)` instead" } else { "called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling \ - `.map_or_else(g, f)` instead" + `.map_or_else(g, f)` instead" }; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_args[1].span, ".."); @@ -2570,11 +2527,7 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( if same_span && !multiline { span_lint_and_note( cx, - if is_option { - OPTION_MAP_UNWRAP_OR_ELSE - } else { - RESULT_MAP_UNWRAP_OR_ELSE - }, + MAP_UNWRAP_OR, expr.span, msg, None, @@ -2584,16 +2537,7 @@ fn lint_map_unwrap_or_else<'a, 'tcx>( ), ); } else if same_span && multiline { - span_lint( - cx, - if is_option { - OPTION_MAP_UNWRAP_OR_ELSE - } else { - RESULT_MAP_UNWRAP_OR_ELSE - }, - expr.span, - msg, - ); + span_lint(cx, MAP_UNWRAP_OR, expr.span, msg); }; } } @@ -2672,73 +2616,6 @@ fn lint_map_or_none<'a, 'tcx>( ); } -/// Lint use of `_.and_then(|x| Some(y))` for `Option`s -fn lint_option_and_then_some(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { - const LINT_MSG: &str = "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"; - const NO_OP_MSG: &str = "using `Option.and_then(Some)`, which is a no-op"; - - let ty = cx.tables.expr_ty(&args[0]); - if !is_type_diagnostic_item(cx, ty, sym!(option_type)) { - return; - } - - match args[1].kind { - hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => { - let closure_body = cx.tcx.hir().body(body_id); - let closure_expr = remove_blocks(&closure_body.value); - if_chain! { - if let hir::ExprKind::Call(ref some_expr, ref some_args) = closure_expr.kind; - if let hir::ExprKind::Path(ref qpath) = some_expr.kind; - if match_qpath(qpath, &paths::OPTION_SOME); - if some_args.len() == 1; - then { - let inner_expr = &some_args[0]; - - if contains_return(inner_expr) { - return; - } - - 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 closure_args_snip = snippet(cx, closure_args_span, ".."); - let option_snip = snippet(cx, args[0].span, ".."); - let note = format!("{}.map({} {})", option_snip, closure_args_snip, some_inner_snip); - span_lint_and_sugg( - cx, - OPTION_AND_THEN_SOME, - expr.span, - LINT_MSG, - "try this", - note, - Applicability::MachineApplicable, - ); - } - } - }, - // `_.and_then(Some)` case, which is no-op. - hir::ExprKind::Path(ref qpath) => { - if match_qpath(qpath, &paths::OPTION_SOME) { - let option_snip = snippet(cx, args[0].span, ".."); - let note = format!("{}", option_snip); - span_lint_and_sugg( - cx, - OPTION_AND_THEN_SOME, - expr.span, - NO_OP_MSG, - "use the expression directly", - note, - Applicability::MachineApplicable, - ); - } - }, - _ => {}, - } -} - /// lint use of `filter().next()` for `Iterators` fn lint_filter_next<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index bf9dd3c936929..20c60ef33189d 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -9,7 +9,7 @@ use rustc_middle::hir::map::Map; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; -use super::OPTION_MAP_UNWRAP_OR; +use super::MAP_UNWRAP_OR; /// lint use of `map().unwrap_or()` for `Option`s pub(super) fn lint<'a, 'tcx>( @@ -62,11 +62,11 @@ pub(super) fn lint<'a, 'tcx>( }; let msg = &format!( "called `map(f).unwrap_or({})` on an `Option` value. \ - This can be done more directly by calling `{}` instead", + This can be done more directly by calling `{}` instead", arg, suggest ); - span_lint_and_then(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, |diag| { + span_lint_and_then(cx, MAP_UNWRAP_OR, expr.span, msg, |diag| { let map_arg_span = map_args[1].span; let mut suggestion = vec![ diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index a21818701dacc..ed48ab548978c 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -293,7 +293,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { ); spans.sort_by_key(|&(span, _)| span); } - multispan_sugg(diag, "consider taking a reference instead".to_string(), spans); + multispan_sugg(diag, "consider taking a reference instead", spans); }; span_lint_and_then( diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index d7ce2e66d69fb..83c6faac04149 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,14 +1,17 @@ +use crate::consts::{constant, Constant}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; +use std::cmp::Ordering; use crate::utils::sugg::Sugg; +use crate::utils::{get_parent_expr, is_integer_const, snippet, snippet_opt, span_lint, span_lint_and_then}; use crate::utils::{higher, SpanlessEq}; -use crate::utils::{is_integer_const, snippet, snippet_opt, span_lint, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for zipping a collection with the range of @@ -84,10 +87,44 @@ declare_clippy_lint! { "`x..=(y-1)` reads better as `x..y`" } +declare_clippy_lint! { + /// **What it does:** Checks for range expressions `x..y` where both `x` and `y` + /// are constant and `x` is greater or equal to `y`. + /// + /// **Why is this bad?** Empty ranges yield no values so iterating them is a no-op. + /// Moreover, trying to use a reversed range to index a slice will panic at run-time. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,no_run + /// fn main() { + /// (10..=0).for_each(|x| println!("{}", x)); + /// + /// let arr = [1, 2, 3, 4, 5]; + /// let sub = &arr[3..1]; + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn main() { + /// (0..=10).rev().for_each(|x| println!("{}", x)); + /// + /// let arr = [1, 2, 3, 4, 5]; + /// let sub = &arr[1..3]; + /// } + /// ``` + pub REVERSED_EMPTY_RANGES, + correctness, + "reversing the limits of range expressions, resulting in empty ranges" +} + declare_lint_pass!(Ranges => [ RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, - RANGE_MINUS_ONE + RANGE_MINUS_ONE, + REVERSED_EMPTY_RANGES, ]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Ranges { @@ -124,6 +161,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Ranges { check_exclusive_range_plus_one(cx, expr); check_inclusive_range_minus_one(cx, expr); + check_reversed_empty_range(cx, expr); } } @@ -202,6 +240,76 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { } } +fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + fn inside_indexing_expr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + matches!( + get_parent_expr(cx, expr), + Some(Expr { + kind: ExprKind::Index(..), + .. + }) + ) + } + + fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool { + match limits { + RangeLimits::HalfOpen => ordering != Ordering::Less, + RangeLimits::Closed => ordering == Ordering::Greater, + } + } + + if_chain! { + if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(cx, expr); + let ty = cx.tables.expr_ty(start); + if let ty::Int(_) | ty::Uint(_) = ty.kind; + if let Some((start_idx, _)) = constant(cx, cx.tables, start); + if let Some((end_idx, _)) = constant(cx, cx.tables, end); + if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); + if is_empty_range(limits, ordering); + then { + if inside_indexing_expr(cx, expr) { + let (reason, outcome) = if ordering == Ordering::Equal { + ("empty", "always yield an empty slice") + } else { + ("reversed", "panic at run-time") + }; + + span_lint( + cx, + REVERSED_EMPTY_RANGES, + expr.span, + &format!("this range is {} and using it to index a slice will {}", reason, outcome), + ); + } else { + span_lint_and_then( + cx, + REVERSED_EMPTY_RANGES, + expr.span, + "this range is empty so it will yield no values", + |diag| { + if ordering != Ordering::Equal { + let start_snippet = snippet(cx, start.span, "_"); + let end_snippet = snippet(cx, end.span, "_"); + let dots = match limits { + RangeLimits::HalfOpen => "..", + RangeLimits::Closed => "..=" + }; + + diag.span_suggestion( + expr.span, + "consider using the following if you are attempting to iterate over this \ + range in reverse", + format!("({}{}{}).rev()", end_snippet, dots, start_snippet), + Applicability::MaybeIncorrect, + ); + } + }, + ); + } + } + } +} + fn y_plus_one<'t>(cx: &LateContext<'_, '_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'t>> { match expr.kind { ExprKind::Binary( diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 5c9117d5b81cd..35464f629c364 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -248,28 +248,7 @@ impl EarlyLintPass for Return { if let ast::TyKind::Tup(ref vals) = ty.kind; if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span); then { - let (rspan, appl) = if let Ok(fn_source) = - cx.sess().source_map() - .span_to_snippet(span.with_hi(ty.span.hi())) { - if let Some(rpos) = fn_source.rfind("->") { - #[allow(clippy::cast_possible_truncation)] - (ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable) - } else { - (ty.span, Applicability::MaybeIncorrect) - } - } else { - (ty.span, Applicability::MaybeIncorrect) - }; - span_lint_and_sugg( - cx, - UNUSED_UNIT, - rspan, - "unneeded unit return type", - "remove the `-> ()`", - String::new(), - appl, - ); + lint_unneeded_unit_return(cx, ty, span); } } } @@ -313,6 +292,22 @@ impl EarlyLintPass for Return { _ => (), } } + + fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) { + let segments = &poly.trait_ref.path.segments; + + if_chain! { + if segments.len() == 1; + if ["Fn", "FnMut", "FnOnce"].contains(&&*segments[0].ident.name.as_str()); + if let Some(args) = &segments[0].args; + if let ast::GenericArgs::Parenthesized(generic_args) = &**args; + if let ast::FnRetTy::Ty(ty) = &generic_args.output; + if ty.kind.is_unit(); + then { + lint_unneeded_unit_return(cx, ty, generic_args.span); + } + } + } } fn attr_is_cfg(attr: &ast::Attribute) -> bool { @@ -337,3 +332,28 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { false } } + +fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { + let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) { + if let Some(rpos) = fn_source.rfind("->") { + #[allow(clippy::cast_possible_truncation)] + ( + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + } else { + (ty.span, Applicability::MaybeIncorrect) + } + } else { + (ty.span, Applicability::MaybeIncorrect) + }; + span_lint_and_sugg( + cx, + UNUSED_UNIT, + ret_span, + "unneeded unit return type", + "remove the `-> ()`", + String::new(), + appl, + ); +} diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 6d49f50d550e8..6ed9ff22e4664 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -2206,7 +2206,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher { multispan_sugg( diag, - "consider adding a type parameter".to_string(), + "consider adding a type parameter", vec![ ( generics_suggestion_span, @@ -2230,7 +2230,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher { ); if !vis.suggestions.is_empty() { - multispan_sugg(diag, "...and use generic constructor".into(), vis.suggestions); + multispan_sugg(diag, "...and use generic constructor", vis.suggestions); } } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index f3844c7d3b68f..8b971e7064b52 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -8,6 +8,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnO use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -90,6 +91,14 @@ fn collect_unwrap_info<'a, 'tcx>( branch: &'tcx Expr<'_>, invert: bool, ) -> Vec> { + fn is_relevant_option_call(cx: &LateContext<'_, '_>, ty: Ty<'_>, method_name: &str) -> bool { + is_type_diagnostic_item(cx, ty, sym!(option_type)) && ["is_some", "is_none"].contains(&method_name) + } + + fn is_relevant_result_call(cx: &LateContext<'_, '_>, ty: Ty<'_>, method_name: &str) -> bool { + is_type_diagnostic_item(cx, ty, sym!(result_type)) && ["is_ok", "is_err"].contains(&method_name) + } + if let ExprKind::Binary(op, left, right) = &expr.kind { match (invert, op.node) { (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => { @@ -106,9 +115,8 @@ fn collect_unwrap_info<'a, 'tcx>( if let ExprKind::MethodCall(method_name, _, args) = &expr.kind; if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind; let ty = cx.tables.expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym!(option_type)) || is_type_diagnostic_item(cx, ty, sym!(result_type)); let name = method_name.ident.as_str(); - if ["is_some", "is_none", "is_ok", "is_err"].contains(&&*name); + if is_relevant_option_call(cx, ty, &name) || is_relevant_result_call(cx, ty, &name); then { assert!(args.len() == 1); let unwrappable = match name.as_ref() { diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/useless_conversion.rs similarity index 84% rename from clippy_lints/src/identity_conversion.rs rename to clippy_lints/src/useless_conversion.rs index 33a9478f05883..95921518986bc 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -7,30 +7,36 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for always-identical `Into`/`From`/`IntoIter` conversions. + /// **What it does:** Checks for `Into`/`From`/`IntoIter` calls that useless converts + /// to the same type as caller. /// /// **Why is this bad?** Redundant code. /// /// **Known problems:** None. /// /// **Example:** + /// /// ```rust + /// // Bad /// // format!() returns a `String` /// let s: String = format!("hello").into(); + /// + /// // Good + /// let s: String = format!("hello"); /// ``` - pub IDENTITY_CONVERSION, + pub USELESS_CONVERSION, complexity, - "using always-identical `Into`/`From`/`IntoIter` conversions" + "calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type" } #[derive(Default)] -pub struct IdentityConversion { +pub struct UselessConversion { try_desugar_arm: Vec, } -impl_lint_pass!(IdentityConversion => [IDENTITY_CONVERSION]); +impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]); -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) { if e.span.from_expansion() { return; @@ -60,9 +66,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { span_lint_and_sugg( cx, - IDENTITY_CONVERSION, + USELESS_CONVERSION, e.span, - "identical conversion", + "useless conversion", "consider removing `.into()`", sugg, Applicability::MachineApplicable, // snippet @@ -76,9 +82,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { let sugg = snippet(cx, args[0].span, "").into_owned(); span_lint_and_sugg( cx, - IDENTITY_CONVERSION, + USELESS_CONVERSION, e.span, - "identical conversion", + "useless conversion", "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -99,9 +105,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( cx, - IDENTITY_CONVERSION, + USELESS_CONVERSION, e.span, - "identical conversion", + "useless conversion", &sugg_msg, sugg, Applicability::MachineApplicable, // snippet diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs index 24a1bdf1883f6..f6d87c8532e43 100644 --- a/clippy_lints/src/utils/diagnostics.rs +++ b/clippy_lints/src/utils/diagnostics.rs @@ -1,6 +1,6 @@ //! Clippy wrappers around rustc's diagnostic functions. -use rustc_errors::{Applicability, CodeSuggestion, DiagnosticBuilder, Substitution, SubstitutionPart, SuggestionStyle}; +use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir::HirId; use rustc_lint::{LateContext, Lint, LintContext}; use rustc_span::source_map::{MultiSpan, Span}; @@ -198,20 +198,20 @@ pub fn span_lint_and_sugg<'a, T: LintContext>( /// appear once per /// replacement. In human-readable format though, it only appears once before /// the whole suggestion. -pub fn multispan_sugg(diag: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I) +pub fn multispan_sugg(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: I) where I: IntoIterator, { - let sugg = CodeSuggestion { - substitutions: vec![Substitution { - parts: sugg - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }], - msg: help_msg, - style: SuggestionStyle::ShowCode, - applicability: Applicability::Unspecified, - }; - diag.suggestions.push(sugg); + multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg) +} + +pub fn multispan_sugg_with_applicability( + diag: &mut DiagnosticBuilder<'_>, + help_msg: &str, + applicability: Applicability, + sugg: I, +) where + I: IntoIterator, +{ + diag.multipart_suggestion(help_msg, sugg.into_iter().collect(), applicability); } diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index e85356779877c..904d948ad29ed 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -77,8 +77,8 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { } pub struct UsedVisitor { - pub var: Symbol, // var to look for - pub used: bool, // has the var been used otherwise? + pub var: Symbol, // var to look for + pub used: bool, // has the var been used otherwise? } impl<'tcx> Visitor<'tcx> for UsedVisitor { diff --git a/src/driver.rs b/src/driver.rs index 1ce0300f23904..d3a7e24937f95 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -295,121 +295,119 @@ fn toolchain_path(home: Option, toolchain: Option) -> Option = env::args().collect(); - - if orig_args.iter().any(|a| a == "--version" || a == "-V") { - let version_info = rustc_tools_util::get_version_info!(); - println!("{}", version_info); - exit(0); - } + exit(rustc_driver::catch_with_exit_code(move || { + let mut orig_args: Vec = env::args().collect(); - // Get the sysroot, looking from most specific to this invocation to the least: - // - command line - // - runtime environment - // - SYSROOT - // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN - // - sysroot from rustc in the path - // - compile-time environment - // - SYSROOT - // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN - let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true); - let have_sys_root_arg = sys_root_arg.is_some(); - let sys_root = sys_root_arg - .map(PathBuf::from) - .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from)) - .or_else(|| { - let home = std::env::var("RUSTUP_HOME") - .or_else(|_| std::env::var("MULTIRUST_HOME")) - .ok(); - let toolchain = std::env::var("RUSTUP_TOOLCHAIN") - .or_else(|_| std::env::var("MULTIRUST_TOOLCHAIN")) - .ok(); - toolchain_path(home, toolchain) - }) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| PathBuf::from(s.trim())) - }) - .or_else(|| option_env!("SYSROOT").map(PathBuf::from)) - .or_else(|| { - let home = option_env!("RUSTUP_HOME") - .or(option_env!("MULTIRUST_HOME")) - .map(ToString::to_string); - let toolchain = option_env!("RUSTUP_TOOLCHAIN") - .or(option_env!("MULTIRUST_TOOLCHAIN")) - .map(ToString::to_string); - toolchain_path(home, toolchain) - }) - .map(|pb| pb.to_string_lossy().to_string()) - .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); - - // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. - // We're invoking the compiler programmatically, so we ignore this/ - let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); - - if wrapper_mode { - // we still want to be able to invoke it normally though - orig_args.remove(1); - } + if orig_args.iter().any(|a| a == "--version" || a == "-V") { + let version_info = rustc_tools_util::get_version_info!(); + println!("{}", version_info); + exit(0); + } - if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) { - display_help(); - exit(0); - } + // Get the sysroot, looking from most specific to this invocation to the least: + // - command line + // - runtime environment + // - SYSROOT + // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN + // - sysroot from rustc in the path + // - compile-time environment + // - SYSROOT + // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN + let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true); + let have_sys_root_arg = sys_root_arg.is_some(); + let sys_root = sys_root_arg + .map(PathBuf::from) + .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from)) + .or_else(|| { + let home = std::env::var("RUSTUP_HOME") + .or_else(|_| std::env::var("MULTIRUST_HOME")) + .ok(); + let toolchain = std::env::var("RUSTUP_TOOLCHAIN") + .or_else(|_| std::env::var("MULTIRUST_TOOLCHAIN")) + .ok(); + toolchain_path(home, toolchain) + }) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| PathBuf::from(s.trim())) + }) + .or_else(|| option_env!("SYSROOT").map(PathBuf::from)) + .or_else(|| { + let home = option_env!("RUSTUP_HOME") + .or(option_env!("MULTIRUST_HOME")) + .map(ToString::to_string); + let toolchain = option_env!("RUSTUP_TOOLCHAIN") + .or(option_env!("MULTIRUST_TOOLCHAIN")) + .map(ToString::to_string); + toolchain_path(home, toolchain) + }) + .map(|pb| pb.to_string_lossy().to_string()) + .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust"); - let should_describe_lints = || { - let args: Vec<_> = env::args().collect(); - args.windows(2).any(|args| { - args[1] == "help" - && match args[0].as_str() { - "-W" | "-A" | "-D" | "-F" => true, - _ => false, - } - }) - }; - - if !wrapper_mode && should_describe_lints() { - describe_lints(); - exit(0); - } + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. + // We're invoking the compiler programmatically, so we ignore this/ + let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref()); + + if wrapper_mode { + // we still want to be able to invoke it normally though + orig_args.remove(1); + } + + if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) { + display_help(); + exit(0); + } + + let should_describe_lints = || { + let args: Vec<_> = env::args().collect(); + args.windows(2).any(|args| { + args[1] == "help" + && match args[0].as_str() { + "-W" | "-A" | "-D" | "-F" => true, + _ => false, + } + }) + }; - // this conditional check for the --sysroot flag is there so users can call - // `clippy_driver` directly - // without having to pass --sysroot or anything - let mut args: Vec = orig_args.clone(); - if !have_sys_root_arg { - args.extend(vec!["--sysroot".into(), sys_root]); - }; - - // this check ensures that dependencies are built but not linted and the final - // crate is linted but not built - let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true") - || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none(); - - if clippy_enabled { - args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); - if let Ok(extra_args) = env::var("CLIPPY_ARGS") { - args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| { - if s.is_empty() { - None - } else { - Some(s.to_string()) - } - })); - } + if !wrapper_mode && should_describe_lints() { + describe_lints(); + exit(0); + } + + // this conditional check for the --sysroot flag is there so users can call + // `clippy_driver` directly + // without having to pass --sysroot or anything + let mut args: Vec = orig_args.clone(); + if !have_sys_root_arg { + args.extend(vec!["--sysroot".into(), sys_root]); + }; + + // this check ensures that dependencies are built but not linted and the final + // crate is linted but not built + let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true") + || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none(); + + if clippy_enabled { + args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]); + if let Ok(extra_args) = env::var("CLIPPY_ARGS") { + args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| { + if s.is_empty() { + None + } else { + Some(s.to_string()) + } + })); } - let mut clippy = ClippyCallbacks; - let mut default = DefaultCallbacks; - let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = - if clippy_enabled { &mut clippy } else { &mut default }; - rustc_driver::run_compiler(&args, callbacks, None, None) - }) - ) + } + let mut clippy = ClippyCallbacks; + let mut default = DefaultCallbacks; + let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = + if clippy_enabled { &mut clippy } else { &mut default }; + rustc_driver::run_compiler(&args, callbacks, None, None) + })) } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 51d1cb2216a95..9457a64f9c6b9 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -67,25 +67,25 @@ pub static ref ALL_LINTS: Vec = vec![ module: "bit_mask", }, Lint { - name: "blacklisted_name", - group: "style", - desc: "usage of a blacklisted/placeholder name", + name: "bind_instead_of_map", + group: "complexity", + desc: "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`", deprecation: None, - module: "blacklisted_name", + module: "methods", }, Lint { - name: "block_in_if_condition_expr", + name: "blacklisted_name", group: "style", - desc: "braces that can be eliminated in conditions, e.g., `if { true } ...`", + desc: "usage of a blacklisted/placeholder name", deprecation: None, - module: "block_in_if_condition", + module: "blacklisted_name", }, Lint { - name: "block_in_if_condition_stmt", + name: "blocks_in_if_conditions", group: "style", - desc: "complex blocks in conditions, e.g., `if { let x = true; x } ...`", + desc: "useless or complex blocks that can be eliminated in conditions", deprecation: None, - module: "block_in_if_condition", + module: "blocks_in_if_conditions", }, Lint { name: "bool_comparison", @@ -521,6 +521,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "methods", }, + Lint { + name: "expect_used", + group: "restriction", + desc: "using `.expect()` on `Result` or `Option`, which might be better handled", + deprecation: None, + module: "methods", + }, Lint { name: "expl_impl_clone_on_copy", group: "pedantic", @@ -676,16 +683,9 @@ pub static ref ALL_LINTS: Vec = vec![ module: "loops", }, Lint { - name: "for_loop_over_option", - group: "correctness", - desc: "for-looping over an `Option`, which is more clearly expressed as an `if let`", - deprecation: None, - module: "loops", - }, - Lint { - name: "for_loop_over_result", + name: "for_loops_over_fallibles", group: "correctness", - desc: "for-looping over a `Result`, which is more clearly expressed as an `if let`", + desc: "for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`", deprecation: None, module: "loops", }, @@ -724,13 +724,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "methods", }, - Lint { - name: "identity_conversion", - group: "complexity", - desc: "using always-identical `Into`/`From`/`IntoIter` conversions", - deprecation: None, - module: "identity_conversion", - }, Lint { name: "identity_op", group: "complexity", @@ -1144,6 +1137,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "methods", }, + Lint { + name: "map_unwrap_or", + group: "pedantic", + desc: "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`", + deprecation: None, + module: "methods", + }, Lint { name: "match_as_ref", group: "complexity", @@ -1578,13 +1578,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "eq_op", }, - Lint { - name: "option_and_then_some", - group: "complexity", - desc: "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`", - deprecation: None, - module: "methods", - }, Lint { name: "option_as_ref_deref", group: "complexity", @@ -1599,13 +1592,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "option_env_unwrap", }, - Lint { - name: "option_expect_used", - group: "restriction", - desc: "using `Option.expect()`, which might be better handled", - deprecation: None, - module: "methods", - }, Lint { name: "option_map_or_none", group: "style", @@ -1620,20 +1606,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "map_unit_fn", }, - Lint { - name: "option_map_unwrap_or", - group: "pedantic", - desc: "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "option_map_unwrap_or_else", - group: "pedantic", - desc: "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`", - deprecation: None, - module: "methods", - }, Lint { name: "option_option", group: "pedantic", @@ -1641,13 +1613,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "types", }, - Lint { - name: "option_unwrap_used", - group: "restriction", - desc: "using `Option.unwrap()`, which should at least get a better message using `expect()`", - deprecation: None, - module: "methods", - }, Lint { name: "or_fun_call", group: "perf", @@ -1886,13 +1851,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "matches", }, - Lint { - name: "result_expect_used", - group: "restriction", - desc: "using `Result.expect()`, which might be better handled", - deprecation: None, - module: "methods", - }, Lint { name: "result_map_or_into_option", group: "style", @@ -1908,25 +1866,11 @@ pub static ref ALL_LINTS: Vec = vec![ module: "map_unit_fn", }, Lint { - name: "result_map_unwrap_or_else", - group: "pedantic", - desc: "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.map_or_else(g, f)`", - deprecation: None, - module: "methods", - }, - Lint { - name: "result_unwrap_used", - group: "restriction", - desc: "using `Result.unwrap()`, which might be better handled", - deprecation: None, - module: "methods", - }, - Lint { - name: "reverse_range_loop", + name: "reversed_empty_ranges", group: "correctness", - desc: "iteration over an empty range, such as `10..0` or `5..5`", + desc: "reversing the limits of range expressions, resulting in empty ranges", deprecation: None, - module: "loops", + module: "ranges", }, Lint { name: "same_functions_in_if_condition", @@ -2425,6 +2369,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "returns", }, + Lint { + name: "unwrap_used", + group: "restriction", + desc: "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`", + deprecation: None, + module: "methods", + }, Lint { name: "use_debug", group: "restriction", @@ -2460,6 +2411,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "attrs", }, + Lint { + name: "useless_conversion", + group: "complexity", + desc: "calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type", + deprecation: None, + module: "useless_conversion", + }, Lint { name: "useless_format", group: "complexity", @@ -2469,7 +2427,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "useless_let_if_seq", - group: "style", + group: "nursery", desc: "unidiomatic `let mut` declaration followed by initialization in `if`", deprecation: None, module: "let_if_seq", diff --git a/tests/ui/option_and_then_some.fixed b/tests/ui/bind_instead_of_map.fixed similarity index 90% rename from tests/ui/option_and_then_some.fixed rename to tests/ui/bind_instead_of_map.fixed index 035bc1e54656b..5815550d7a6a1 100644 --- a/tests/ui/option_and_then_some.fixed +++ b/tests/ui/bind_instead_of_map.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![deny(clippy::option_and_then_some)] +#![deny(clippy::bind_instead_of_map)] // need a main anyway, use it get rid of unused warnings too pub fn main() { @@ -12,7 +12,7 @@ pub fn main() { // Different type let x: Result = Ok(1); - let _ = x.and_then(Ok); + let _ = x; } pub fn foo() -> Option { diff --git a/tests/ui/option_and_then_some.rs b/tests/ui/bind_instead_of_map.rs similarity index 94% rename from tests/ui/option_and_then_some.rs rename to tests/ui/bind_instead_of_map.rs index d49da7813c6e6..623b100a4ce7e 100644 --- a/tests/ui/option_and_then_some.rs +++ b/tests/ui/bind_instead_of_map.rs @@ -1,5 +1,5 @@ // run-rustfix -#![deny(clippy::option_and_then_some)] +#![deny(clippy::bind_instead_of_map)] // need a main anyway, use it get rid of unused warnings too pub fn main() { diff --git a/tests/ui/option_and_then_some.stderr b/tests/ui/bind_instead_of_map.stderr similarity index 50% rename from tests/ui/option_and_then_some.stderr rename to tests/ui/bind_instead_of_map.stderr index 4782549176566..24c6b7f9ef32b 100644 --- a/tests/ui/option_and_then_some.stderr +++ b/tests/ui/bind_instead_of_map.stderr @@ -1,20 +1,26 @@ error: using `Option.and_then(Some)`, which is a no-op - --> $DIR/option_and_then_some.rs:8:13 + --> $DIR/bind_instead_of_map.rs:8:13 | LL | let _ = x.and_then(Some); | ^^^^^^^^^^^^^^^^ help: use the expression directly: `x` | note: the lint level is defined here - --> $DIR/option_and_then_some.rs:2:9 + --> $DIR/bind_instead_of_map.rs:2:9 | -LL | #![deny(clippy::option_and_then_some)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::bind_instead_of_map)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` - --> $DIR/option_and_then_some.rs:9:13 + --> $DIR/bind_instead_of_map.rs:9:13 | LL | let _ = x.and_then(|o| Some(o + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.map(|o| o + 1)` -error: aborting due to 2 previous errors +error: using `Result.and_then(Ok)`, which is a no-op + --> $DIR/bind_instead_of_map.rs:15:13 + | +LL | let _ = x.and_then(Ok); + | ^^^^^^^^^^^^^^ help: use the expression directly: `x` + +error: aborting due to 3 previous errors diff --git a/tests/ui/bind_instead_of_map_multipart.rs b/tests/ui/bind_instead_of_map_multipart.rs new file mode 100644 index 0000000000000..91d9d11e3c110 --- /dev/null +++ b/tests/ui/bind_instead_of_map_multipart.rs @@ -0,0 +1,61 @@ +#![deny(clippy::bind_instead_of_map)] +#![allow(clippy::blocks_in_if_conditions)] + +pub fn main() { + let _ = Some("42").and_then(|s| if s.len() < 42 { Some(0) } else { Some(s.len()) }); + let _ = Some("42").and_then(|s| if s.len() < 42 { None } else { Some(s.len()) }); + + let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) }); + let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Err(()) } else { Ok(s.len()) }); + + let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) }); + let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Ok(()) } else { Err(s.len()) }); + + hard_example(); + macro_example(); +} + +fn hard_example() { + Some("42").and_then(|s| { + if { + if s == "43" { + return Some(43); + } + s == "42" + } { + return Some(45); + } + match s.len() { + 10 => Some(2), + 20 => { + if foo() { + return { + if foo() { + return Some(20); + } + println!("foo"); + Some(3) + }; + } + Some(20) + }, + 40 => Some(30), + _ => Some(1), + } + }); +} + +fn foo() -> bool { + true +} + +macro_rules! m { + () => { + Some(10) + }; +} + +fn macro_example() { + let _ = Some("").and_then(|s| if s.len() == 20 { m!() } else { Some(20) }); + let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) }); +} diff --git a/tests/ui/bind_instead_of_map_multipart.stderr b/tests/ui/bind_instead_of_map_multipart.stderr new file mode 100644 index 0000000000000..50ce2f4051e00 --- /dev/null +++ b/tests/ui/bind_instead_of_map_multipart.stderr @@ -0,0 +1,73 @@ +error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` + --> $DIR/bind_instead_of_map_multipart.rs:5:13 + | +LL | let _ = Some("42").and_then(|s| if s.len() < 42 { Some(0) } else { Some(s.len()) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/bind_instead_of_map_multipart.rs:1:9 + | +LL | #![deny(clippy::bind_instead_of_map)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: try this + | +LL | let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); + | ^^^ ^ ^^^^^^^ + +error: using `Result.and_then(|x| Ok(y))`, which is more succinctly expressed as `map(|x| y)` + --> $DIR/bind_instead_of_map_multipart.rs:8:13 + | +LL | let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try this + | +LL | let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); + | ^^^ ^ ^^^^^^^ + +error: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as `map_err(|x| y)` + --> $DIR/bind_instead_of_map_multipart.rs:11:13 + | +LL | let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try this + | +LL | let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } else { s.len() }); + | ^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^ + +error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` + --> $DIR/bind_instead_of_map_multipart.rs:19:5 + | +LL | / Some("42").and_then(|s| { +LL | | if { +LL | | if s == "43" { +LL | | return Some(43); +... | +LL | | } +LL | | }); + | |______^ + | +help: try this + | +LL | Some("42").map(|s| { +LL | if { +LL | if s == "43" { +LL | return 43; +LL | } +LL | s == "42" + ... + +error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` + --> $DIR/bind_instead_of_map_multipart.rs:60:13 + | +LL | let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try this + | +LL | let _ = Some("").map(|s| if s.len() == 20 { m!() } else { Some(20) }); + | ^^^ ^^^^ ^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/block_in_if_condition.fixed b/tests/ui/blocks_in_if_conditions.fixed similarity index 88% rename from tests/ui/block_in_if_condition.fixed rename to tests/ui/blocks_in_if_conditions.fixed index 955801e40f9b7..14562c4d32c12 100644 --- a/tests/ui/block_in_if_condition.fixed +++ b/tests/ui/blocks_in_if_conditions.fixed @@ -1,6 +1,5 @@ // run-rustfix -#![warn(clippy::block_in_if_condition_expr)] -#![warn(clippy::block_in_if_condition_stmt)] +#![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] #![warn(clippy::nonminimal_bool)] @@ -64,10 +63,10 @@ fn block_in_assert() { let opt = Some(42); assert!(opt .as_ref() - .and_then(|val| { + .map(|val| { let mut v = val * 2; v -= 1; - Some(v * 3) + v * 3 }) .is_some()); } diff --git a/tests/ui/block_in_if_condition.rs b/tests/ui/blocks_in_if_conditions.rs similarity index 88% rename from tests/ui/block_in_if_condition.rs rename to tests/ui/blocks_in_if_conditions.rs index a6ea01d5fc5f9..bda87650f6da2 100644 --- a/tests/ui/block_in_if_condition.rs +++ b/tests/ui/blocks_in_if_conditions.rs @@ -1,6 +1,5 @@ // run-rustfix -#![warn(clippy::block_in_if_condition_expr)] -#![warn(clippy::block_in_if_condition_stmt)] +#![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] #![warn(clippy::nonminimal_bool)] @@ -64,10 +63,10 @@ fn block_in_assert() { let opt = Some(42); assert!(opt .as_ref() - .and_then(|val| { + .map(|val| { let mut v = val * 2; v -= 1; - Some(v * 3) + v * 3 }) .is_some()); } diff --git a/tests/ui/block_in_if_condition.stderr b/tests/ui/blocks_in_if_conditions.stderr similarity index 71% rename from tests/ui/block_in_if_condition.stderr rename to tests/ui/blocks_in_if_conditions.stderr index b0a0a276c8908..9bdddc8e15248 100644 --- a/tests/ui/block_in_if_condition.stderr +++ b/tests/ui/blocks_in_if_conditions.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> $DIR/block_in_if_condition.rs:27:5 + --> $DIR/blocks_in_if_conditions.rs:26:5 | LL | / if { LL | | let x = 3; @@ -7,7 +7,7 @@ LL | | x == 3 LL | | } { | |_____^ | - = note: `-D clippy::block-in-if-condition-stmt` implied by `-D warnings` + = note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` help: try | LL | let res = { @@ -17,15 +17,13 @@ LL | }; if res { | error: omit braces around single expression condition - --> $DIR/block_in_if_condition.rs:38:8 + --> $DIR/blocks_in_if_conditions.rs:37:8 | LL | if { true } { | ^^^^^^^^ help: try: `true` - | - = note: `-D clippy::block-in-if-condition-expr` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/block_in_if_condition.rs:47:8 + --> $DIR/blocks_in_if_conditions.rs:46:8 | LL | if true && x == 3 { | ^^^^^^^^^^^^^^ help: try: `x == 3` diff --git a/tests/ui/block_in_if_condition_closure.rs b/tests/ui/blocks_in_if_conditions_closure.rs similarity index 85% rename from tests/ui/block_in_if_condition_closure.rs rename to tests/ui/blocks_in_if_conditions_closure.rs index bac3eda5e7f37..acbabfa20d737 100644 --- a/tests/ui/block_in_if_condition_closure.rs +++ b/tests/ui/blocks_in_if_conditions_closure.rs @@ -1,5 +1,4 @@ -#![warn(clippy::block_in_if_condition_expr)] -#![warn(clippy::block_in_if_condition_stmt)] +#![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] fn predicate bool, T>(pfn: F, val: T) -> bool { @@ -10,7 +9,7 @@ fn pred_test() { let v = 3; let sky = "blue"; // This is a sneaky case, where the block isn't directly in the condition, - // but is actually nside a closure that the condition is using. + // but is actually inside a closure that the condition is using. // The same principle applies -- add some extra expressions to make sure // linter isn't confused by them. if v == 3 diff --git a/tests/ui/block_in_if_condition_closure.stderr b/tests/ui/blocks_in_if_conditions_closure.stderr similarity index 78% rename from tests/ui/block_in_if_condition_closure.stderr rename to tests/ui/blocks_in_if_conditions_closure.stderr index 86cd24fe76321..941d604dd5f91 100644 --- a/tests/ui/block_in_if_condition_closure.stderr +++ b/tests/ui/blocks_in_if_conditions_closure.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> $DIR/block_in_if_condition_closure.rs:19:17 + --> $DIR/blocks_in_if_conditions_closure.rs:18:17 | LL | |x| { | _________________^ @@ -8,10 +8,10 @@ LL | | x == target LL | | }, | |_____________^ | - = note: `-D clippy::block-in-if-condition-stmt` implied by `-D warnings` + = note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> $DIR/block_in_if_condition_closure.rs:28:13 + --> $DIR/blocks_in_if_conditions_closure.rs:27:13 | LL | |x| { | _____________^ diff --git a/tests/ui/comparison_chain.rs b/tests/ui/comparison_chain.rs index 9c2128469de9d..3b03f8c7dfe7c 100644 --- a/tests/ui/comparison_chain.rs +++ b/tests/ui/comparison_chain.rs @@ -137,4 +137,70 @@ fn h(x: T, y: T, z: T) { } } +// The following uses should be ignored +mod issue_5212 { + use super::{a, b, c}; + fn foo() -> u8 { + 21 + } + + fn same_operation_equals() { + // operands are fixed + + if foo() == 42 { + a() + } else if foo() == 42 { + b() + } + + if foo() == 42 { + a() + } else if foo() == 42 { + b() + } else { + c() + } + + // operands are transposed + + if foo() == 42 { + a() + } else if 42 == foo() { + b() + } + } + + fn same_operation_not_equals() { + // operands are fixed + + if foo() > 42 { + a() + } else if foo() > 42 { + b() + } + + if foo() > 42 { + a() + } else if foo() > 42 { + b() + } else { + c() + } + + if foo() < 42 { + a() + } else if foo() < 42 { + b() + } + + if foo() < 42 { + a() + } else if foo() < 42 { + b() + } else { + c() + } + } +} + fn main() {} diff --git a/tests/ui/crashes/ice-5579.rs b/tests/ui/crashes/ice-5579.rs new file mode 100644 index 0000000000000..e1842c73f0e31 --- /dev/null +++ b/tests/ui/crashes/ice-5579.rs @@ -0,0 +1,17 @@ +trait IsErr { + fn is_err(&self, err: &str) -> bool; +} + +impl IsErr for Option { + fn is_err(&self, _err: &str) -> bool { + true + } +} + +fn main() { + let t = Some(1); + + if t.is_err("") { + t.unwrap(); + } +} diff --git a/tests/ui/expect.rs b/tests/ui/expect.rs index 0bd4252c49aa5..1073acf6f0cd6 100644 --- a/tests/ui/expect.rs +++ b/tests/ui/expect.rs @@ -1,4 +1,4 @@ -#![warn(clippy::option_expect_used, clippy::result_expect_used)] +#![warn(clippy::expect_used)] fn expect_option() { let opt = Some(0); diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index adf9f4f192191..9d3fc7df15cc7 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -4,7 +4,7 @@ error: used `expect()` on `an Option` value LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | - = note: `-D clippy::option-expect-used` implied by `-D warnings` + = note: `-D clippy::expect-used` implied by `-D warnings` = help: if this value is an `None`, it will panic error: used `expect()` on `a Result` value @@ -13,7 +13,6 @@ error: used `expect()` on `a Result` value LL | let _ = res.expect(""); | ^^^^^^^^^^^^^^ | - = note: `-D clippy::result-expect-used` implied by `-D warnings` = help: if this value is an `Err`, it will panic error: aborting due to 2 previous errors diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed index 5fc84ada9efdd..249a88a0b3982 100644 --- a/tests/ui/for_loop_fixable.fixed +++ b/tests/ui/for_loop_fixable.fixed @@ -21,7 +21,6 @@ impl Unrelated { clippy::explicit_iter_loop, clippy::explicit_into_iter_loop, clippy::iter_next_loop, - clippy::reverse_range_loop, clippy::for_kv_map )] #[allow( @@ -32,61 +31,8 @@ impl Unrelated { )] #[allow(clippy::many_single_char_names, unused_variables)] fn main() { - const MAX_LEN: usize = 42; let mut vec = vec![1, 2, 3, 4]; - for i in (0..10).rev() { - println!("{}", i); - } - - for i in (0..=10).rev() { - println!("{}", i); - } - - for i in (0..MAX_LEN).rev() { - println!("{}", i); - } - - for i in 5..=5 { - // not an error, this is the range with only one element “5” - println!("{}", i); - } - - for i in 0..10 { - // not an error, the start index is less than the end index - println!("{}", i); - } - - for i in -10..0 { - // not an error - println!("{}", i); - } - - for i in (10..0).map(|x| x * 2) { - // not an error, it can't be known what arbitrary methods do to a range - println!("{}", i); - } - - // testing that the empty range lint folds constants - for i in (5 + 4..10).rev() { - println!("{}", i); - } - - for i in ((3 - 1)..(5 + 2)).rev() { - println!("{}", i); - } - - for i in (2 * 2)..(2 * 3) { - // no error, 4..6 is fine - println!("{}", i); - } - - let x = 42; - for i in x..10 { - // no error, not constant-foldable - println!("{}", i); - } - // See #601 for i in 0..10 { // no error, id_col does not exist outside the loop diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs index 4165b0dc00494..306d85a6351e1 100644 --- a/tests/ui/for_loop_fixable.rs +++ b/tests/ui/for_loop_fixable.rs @@ -21,7 +21,6 @@ impl Unrelated { clippy::explicit_iter_loop, clippy::explicit_into_iter_loop, clippy::iter_next_loop, - clippy::reverse_range_loop, clippy::for_kv_map )] #[allow( @@ -32,61 +31,8 @@ impl Unrelated { )] #[allow(clippy::many_single_char_names, unused_variables)] fn main() { - const MAX_LEN: usize = 42; let mut vec = vec![1, 2, 3, 4]; - for i in 10..0 { - println!("{}", i); - } - - for i in 10..=0 { - println!("{}", i); - } - - for i in MAX_LEN..0 { - println!("{}", i); - } - - for i in 5..=5 { - // not an error, this is the range with only one element “5” - println!("{}", i); - } - - for i in 0..10 { - // not an error, the start index is less than the end index - println!("{}", i); - } - - for i in -10..0 { - // not an error - println!("{}", i); - } - - for i in (10..0).map(|x| x * 2) { - // not an error, it can't be known what arbitrary methods do to a range - println!("{}", i); - } - - // testing that the empty range lint folds constants - for i in 10..5 + 4 { - println!("{}", i); - } - - for i in (5 + 2)..(3 - 1) { - println!("{}", i); - } - - for i in (2 * 2)..(2 * 3) { - // no error, 4..6 is fine - println!("{}", i); - } - - let x = 42; - for i in x..10 { - // no error, not constant-foldable - println!("{}", i); - } - // See #601 for i in 0..10 { // no error, id_col does not exist outside the loop diff --git a/tests/ui/for_loop_fixable.stderr b/tests/ui/for_loop_fixable.stderr index cffb4b9f0a9c0..ddfe66d675f91 100644 --- a/tests/ui/for_loop_fixable.stderr +++ b/tests/ui/for_loop_fixable.stderr @@ -1,61 +1,5 @@ -error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:38:14 - | -LL | for i in 10..0 { - | ^^^^^ - | - = note: `-D clippy::reverse-range-loop` implied by `-D warnings` -help: consider using the following if you are attempting to iterate over this range in reverse - | -LL | for i in (0..10).rev() { - | ^^^^^^^^^^^^^ - -error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:42:14 - | -LL | for i in 10..=0 { - | ^^^^^^ - | -help: consider using the following if you are attempting to iterate over this range in reverse - | -LL | for i in (0..=10).rev() { - | ^^^^^^^^^^^^^^ - -error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:46:14 - | -LL | for i in MAX_LEN..0 { - | ^^^^^^^^^^ - | -help: consider using the following if you are attempting to iterate over this range in reverse - | -LL | for i in (0..MAX_LEN).rev() { - | ^^^^^^^^^^^^^^^^^^ - -error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:71:14 - | -LL | for i in 10..5 + 4 { - | ^^^^^^^^^ - | -help: consider using the following if you are attempting to iterate over this range in reverse - | -LL | for i in (5 + 4..10).rev() { - | ^^^^^^^^^^^^^^^^^ - -error: this range is empty so this for loop will never run - --> $DIR/for_loop_fixable.rs:75:14 - | -LL | for i in (5 + 2)..(3 - 1) { - | ^^^^^^^^^^^^^^^^ - | -help: consider using the following if you are attempting to iterate over this range in reverse - | -LL | for i in ((3 - 1)..(5 + 2)).rev() { - | ^^^^^^^^^^^^^^^^^^^^^^^^ - error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:97:15 + --> $DIR/for_loop_fixable.rs:43:15 | LL | for _v in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -63,13 +7,13 @@ LL | for _v in vec.iter() {} = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:99:15 + --> $DIR/for_loop_fixable.rs:45:15 | LL | for _v in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:102:15 + --> $DIR/for_loop_fixable.rs:48:15 | LL | for _v in out_vec.into_iter() {} | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` @@ -77,76 +21,76 @@ LL | for _v in out_vec.into_iter() {} = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:107:15 + --> $DIR/for_loop_fixable.rs:53:15 | LL | for _v in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:111:15 + --> $DIR/for_loop_fixable.rs:57:15 | LL | for _v in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:116:15 + --> $DIR/for_loop_fixable.rs:62:15 | LL | for _v in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:119:15 + --> $DIR/for_loop_fixable.rs:65:15 | LL | for _v in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:122:15 + --> $DIR/for_loop_fixable.rs:68:15 | LL | for _v in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:125:15 + --> $DIR/for_loop_fixable.rs:71:15 | LL | for _v in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:128:15 + --> $DIR/for_loop_fixable.rs:74:15 | LL | for _v in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:131:15 + --> $DIR/for_loop_fixable.rs:77:15 | LL | for _v in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:134:15 + --> $DIR/for_loop_fixable.rs:80:15 | LL | for _v in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:309:18 + --> $DIR/for_loop_fixable.rs:255:18 | LL | for i in iterator.into_iter() { | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:329:18 + --> $DIR/for_loop_fixable.rs:275:18 | LL | for _ in t.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:331:18 + --> $DIR/for_loop_fixable.rs:277:18 | LL | for _ in r.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` -error: aborting due to 20 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/for_loop_unfixable.rs b/tests/ui/for_loop_unfixable.rs index 179b255e08ca7..e73536052f0f5 100644 --- a/tests/ui/for_loop_unfixable.rs +++ b/tests/ui/for_loop_unfixable.rs @@ -5,7 +5,6 @@ clippy::explicit_iter_loop, clippy::explicit_into_iter_loop, clippy::iter_next_loop, - clippy::reverse_range_loop, clippy::for_kv_map )] #[allow( @@ -16,25 +15,8 @@ unused, dead_code )] -#[allow(clippy::many_single_char_names, unused_variables)] fn main() { - for i in 5..5 { - println!("{}", i); - } - let vec = vec![1, 2, 3, 4]; for _v in vec.iter().next() {} - - for i in (5 + 2)..(8 - 1) { - println!("{}", i); - } - - const ZERO: usize = 0; - - for i in ZERO..vec.len() { - if f(&vec[i], &vec[i]) { - panic!("at the disco"); - } - } } diff --git a/tests/ui/for_loop_unfixable.stderr b/tests/ui/for_loop_unfixable.stderr index 1da8e0f3588d7..1c9287b6acbb3 100644 --- a/tests/ui/for_loop_unfixable.stderr +++ b/tests/ui/for_loop_unfixable.stderr @@ -1,9 +1,10 @@ -error[E0425]: cannot find function `f` in this scope - --> $DIR/for_loop_unfixable.rs:36:12 +error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want + --> $DIR/for_loop_unfixable.rs:21:15 | -LL | if f(&vec[i], &vec[i]) { - | ^ help: a local variable with a similar name exists: `i` +LL | for _v in vec.iter().next() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::iter-next-loop` implied by `-D warnings` error: aborting due to previous error -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/for_loop_over_option_result.rs b/tests/ui/for_loops_over_fallibles.rs similarity index 81% rename from tests/ui/for_loop_over_option_result.rs rename to tests/ui/for_loops_over_fallibles.rs index 6b207b26b6b79..1b9dde87cd5a2 100644 --- a/tests/ui/for_loop_over_option_result.rs +++ b/tests/ui/for_loops_over_fallibles.rs @@ -1,18 +1,16 @@ -#![warn(clippy::for_loop_over_option, clippy::for_loop_over_result)] +#![warn(clippy::for_loops_over_fallibles)] -/// Tests for_loop_over_result and for_loop_over_option - -fn for_loop_over_option_and_result() { +fn for_loops_over_fallibles() { let option = Some(1); let result = option.ok_or("x not found"); let v = vec![0, 1, 2]; - // check FOR_LOOP_OVER_OPTION lint + // check over an `Option` for x in option { println!("{}", x); } - // check FOR_LOOP_OVER_RESULT lint + // check over a `Result` for x in result { println!("{}", x); } diff --git a/tests/ui/for_loop_over_option_result.stderr b/tests/ui/for_loops_over_fallibles.stderr similarity index 81% rename from tests/ui/for_loop_over_option_result.stderr rename to tests/ui/for_loops_over_fallibles.stderr index 194a0bfec5b32..bef228d4b93af 100644 --- a/tests/ui/for_loop_over_option_result.stderr +++ b/tests/ui/for_loops_over_fallibles.stderr @@ -1,23 +1,22 @@ error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:11:14 + --> $DIR/for_loops_over_fallibles.rs:9:14 | LL | for x in option { | ^^^^^^ | - = note: `-D clippy::for-loop-over-option` implied by `-D warnings` + = note: `-D clippy::for-loops-over-fallibles` implied by `-D warnings` = help: consider replacing `for x in option` with `if let Some(x) = option` error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:16:14 + --> $DIR/for_loops_over_fallibles.rs:14:14 | LL | for x in result { | ^^^^^^ | - = note: `-D clippy::for-loop-over-result` implied by `-D warnings` = help: consider replacing `for x in result` with `if let Ok(x) = result` error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:20:14 + --> $DIR/for_loops_over_fallibles.rs:18:14 | LL | for x in option.ok_or("x not found") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +24,7 @@ LL | for x in option.ok_or("x not found") { = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")` error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop_over_option_result.rs:26:14 + --> $DIR/for_loops_over_fallibles.rs:24:14 | LL | for x in v.iter().next() { | ^^^^^^^^^^^^^^^ @@ -33,7 +32,7 @@ LL | for x in v.iter().next() { = note: `#[deny(clippy::iter_next_loop)]` on by default error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:31:14 + --> $DIR/for_loops_over_fallibles.rs:29:14 | LL | for x in v.iter().next().and(Some(0)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +40,7 @@ LL | for x in v.iter().next().and(Some(0)) { = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))` error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement. - --> $DIR/for_loop_over_option_result.rs:35:14 + --> $DIR/for_loops_over_fallibles.rs:33:14 | LL | for x in v.iter().next().ok_or("x not found") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +48,7 @@ LL | for x in v.iter().next().ok_or("x not found") { = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")` error: this loop never actually loops - --> $DIR/for_loop_over_option_result.rs:47:5 + --> $DIR/for_loops_over_fallibles.rs:45:5 | LL | / while let Some(x) = option { LL | | println!("{}", x); @@ -60,7 +59,7 @@ LL | | } = note: `#[deny(clippy::never_loop)]` on by default error: this loop never actually loops - --> $DIR/for_loop_over_option_result.rs:53:5 + --> $DIR/for_loops_over_fallibles.rs:51:5 | LL | / while let Ok(x) = result { LL | | println!("{}", x); diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index ae2815d345a94..ceaacaaf6bd70 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -33,4 +33,9 @@ fn main() { let u: u8 = 0; u & 255; + + 1 << 0; // no error, this case is allowed, see issue 3430 + 42 << 0; + 1 >> 0; + 42 >> 0; } diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr index 4742877706acd..d8d44a74f9ab0 100644 --- a/tests/ui/identity_op.stderr +++ b/tests/ui/identity_op.stderr @@ -48,5 +48,23 @@ error: the operation is ineffective. Consider reducing it to `u` LL | u & 255; | ^^^^^^^ -error: aborting due to 8 previous errors +error: the operation is ineffective. Consider reducing it to `42` + --> $DIR/identity_op.rs:38:5 + | +LL | 42 << 0; + | ^^^^^^^ + +error: the operation is ineffective. Consider reducing it to `1` + --> $DIR/identity_op.rs:39:5 + | +LL | 1 >> 0; + | ^^^^^^ + +error: the operation is ineffective. Consider reducing it to `42` + --> $DIR/identity_op.rs:40:5 + | +LL | 42 >> 0; + | ^^^^^^^ + +error: aborting due to 11 previous errors diff --git a/tests/ui/implicit_saturating_sub.fixed b/tests/ui/implicit_saturating_sub.fixed index e0b5b31a00c7c..859765d08a70b 100644 --- a/tests/ui/implicit_saturating_sub.fixed +++ b/tests/ui/implicit_saturating_sub.fixed @@ -29,8 +29,8 @@ fn main() { // Lint u_16 = u_16.saturating_sub(1); - let mut end_32: u32 = 7000; - let mut start_32: u32 = 7010; + let mut end_32: u32 = 7010; + let mut start_32: u32 = 7000; let mut u_32: u32 = end_32 - start_32; diff --git a/tests/ui/implicit_saturating_sub.rs b/tests/ui/implicit_saturating_sub.rs index 39d8160892297..24cb216e79bf3 100644 --- a/tests/ui/implicit_saturating_sub.rs +++ b/tests/ui/implicit_saturating_sub.rs @@ -35,8 +35,8 @@ fn main() { u_16 -= 1; } - let mut end_32: u32 = 7000; - let mut start_32: u32 = 7010; + let mut end_32: u32 = 7010; + let mut start_32: u32 = 7000; let mut u_32: u32 = end_32 - start_32; diff --git a/tests/ui/manual_memcpy.rs b/tests/ui/manual_memcpy.rs index 9c24d6d4db1f2..0083f94798fe4 100644 --- a/tests/ui/manual_memcpy.rs +++ b/tests/ui/manual_memcpy.rs @@ -104,7 +104,7 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { dst[i - 0] = src[i]; } - #[allow(clippy::reverse_range_loop)] + #[allow(clippy::reversed_empty_ranges)] for i in 0..0 { dst[i] = src[i]; } diff --git a/tests/ui/option_map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs similarity index 75% rename from tests/ui/option_map_unwrap_or.rs rename to tests/ui/map_unwrap_or.rs index 0364d83663a06..585944032e70d 100644 --- a/tests/ui/option_map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -1,21 +1,18 @@ // FIXME: Add "run-rustfix" once it's supported for multipart suggestions // aux-build:option_helpers.rs -#![warn(clippy::option_map_unwrap_or, clippy::option_map_unwrap_or_else)] +#![warn(clippy::map_unwrap_or)] #[macro_use] extern crate option_helpers; use std::collections::HashMap; -/// Checks implementation of the following lints: -/// * `OPTION_MAP_UNWRAP_OR` -/// * `OPTION_MAP_UNWRAP_OR_ELSE` #[rustfmt::skip] fn option_methods() { let opt = Some(1); - // Check `OPTION_MAP_UNWRAP_OR`. + // Check for `option.map(_).unwrap_or(_)` use. // Single line case. let _ = opt.map(|x| x + 1) // Should lint even though this call is on a separate line. @@ -49,7 +46,7 @@ fn option_methods() { let id: String = "identifier".to_string(); let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); - // Check OPTION_MAP_UNWRAP_OR_ELSE + // Check for `option.map(_).unwrap_or_else(_)` use. // single line case let _ = opt.map(|x| x + 1) // Should lint even though this call is on a separate line. @@ -83,6 +80,20 @@ fn option_methods() { } } +fn result_methods() { + let res: Result = Ok(1); + + // Check for `result.map(_).unwrap_or_else(_)` use. + // single line case + let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line + // multi line cases + let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); + let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); + // macro case + let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|e| 0); // should not lint +} + fn main() { option_methods(); + result_methods(); } diff --git a/tests/ui/option_map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr similarity index 70% rename from tests/ui/option_map_unwrap_or.stderr rename to tests/ui/map_unwrap_or.stderr index f05f2893de23a..b62080a073f35 100644 --- a/tests/ui/option_map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -1,5 +1,5 @@ error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/option_map_unwrap_or.rs:20:13 + --> $DIR/map_unwrap_or.rs:17:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -7,14 +7,14 @@ LL | | // Should lint even though this call is on a separate line. LL | | .unwrap_or(0); | |_____________________^ | - = note: `-D clippy::option-map-unwrap-or` implied by `-D warnings` + = note: `-D clippy::map-unwrap-or` implied by `-D warnings` help: use `map_or(a, f)` instead | LL | let _ = opt.map_or(0, |x| x + 1); | ^^^^^^ ^^ -- error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/option_map_unwrap_or.rs:24:13 + --> $DIR/map_unwrap_or.rs:21:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -32,7 +32,7 @@ LL | ); | error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/option_map_unwrap_or.rs:28:13 + --> $DIR/map_unwrap_or.rs:25:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -49,7 +49,7 @@ LL | }, |x| x + 1); | error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/option_map_unwrap_or.rs:33:13 + --> $DIR/map_unwrap_or.rs:30:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _ = opt.and_then(|x| Some(x + 1)); | ^^^^^^^^ -- error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/option_map_unwrap_or.rs:35:13 + --> $DIR/map_unwrap_or.rs:32:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -78,7 +78,7 @@ LL | ); | error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/option_map_unwrap_or.rs:39:13 + --> $DIR/map_unwrap_or.rs:36:13 | LL | let _ = opt | _____________^ @@ -92,7 +92,7 @@ LL | .and_then(|x| Some(x + 1)); | ^^^^^^^^ -- error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/option_map_unwrap_or.rs:50:13 + --> $DIR/map_unwrap_or.rs:47:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | let _ = Some("prefix").map_or(id, |p| format!("{}.", p)); | ^^^^^^ ^^^ -- error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/option_map_unwrap_or.rs:54:13 + --> $DIR/map_unwrap_or.rs:51:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -111,11 +111,10 @@ LL | | // Should lint even though this call is on a separate line. LL | | .unwrap_or_else(|| 0); | |_____________________________^ | - = note: `-D clippy::option-map-unwrap-or-else` implied by `-D warnings` = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)` error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/option_map_unwrap_or.rs:58:13 + --> $DIR/map_unwrap_or.rs:55:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -125,7 +124,7 @@ LL | | ).unwrap_or_else(|| 0); | |__________________________^ error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/option_map_unwrap_or.rs:62:13 + --> $DIR/map_unwrap_or.rs:59:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -134,5 +133,29 @@ LL | | 0 LL | | ); | |_________^ -error: aborting due to 10 previous errors +error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead + --> $DIR/map_unwrap_or.rs:88:13 + | +LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` + +error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead + --> $DIR/map_unwrap_or.rs:90:13 + | +LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` + +error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead + --> $DIR/map_unwrap_or.rs:91:13 + | +LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` + +error: aborting due to 13 previous errors diff --git a/tests/ui/option_map_or_none.fixed b/tests/ui/option_map_or_none.fixed index decbae4e5af9a..d80c3c7c1b722 100644 --- a/tests/ui/option_map_or_none.fixed +++ b/tests/ui/option_map_or_none.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(clippy::option_and_then_some)] +#![allow(clippy::bind_instead_of_map)] fn main() { let opt = Some(1); diff --git a/tests/ui/option_map_or_none.rs b/tests/ui/option_map_or_none.rs index 0f1d2218d5d38..629842419e546 100644 --- a/tests/ui/option_map_or_none.rs +++ b/tests/ui/option_map_or_none.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(clippy::option_and_then_some)] +#![allow(clippy::bind_instead_of_map)] fn main() { let opt = Some(1); diff --git a/tests/ui/result_map_unwrap_or_else.rs b/tests/ui/result_map_unwrap_or_else.rs deleted file mode 100644 index 40751bfebe6c9..0000000000000 --- a/tests/ui/result_map_unwrap_or_else.rs +++ /dev/null @@ -1,23 +0,0 @@ -// aux-build:option_helpers.rs - -//! Checks implementation of `RESULT_MAP_UNWRAP_OR_ELSE` - -#![warn(clippy::result_map_unwrap_or_else)] - -#[macro_use] -extern crate option_helpers; - -fn result_methods() { - let res: Result = Ok(1); - - // Check RESULT_MAP_UNWRAP_OR_ELSE - // single line case - let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line - // multi line cases - let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - // macro case - let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|e| 0); // should not lint -} - -fn main() {} diff --git a/tests/ui/result_map_unwrap_or_else.stderr b/tests/ui/result_map_unwrap_or_else.stderr deleted file mode 100644 index ec7bc8f12414f..0000000000000 --- a/tests/ui/result_map_unwrap_or_else.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead - --> $DIR/result_map_unwrap_or_else.rs:15:13 - | -LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::result-map-unwrap-or-else` implied by `-D warnings` - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` - -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead - --> $DIR/result_map_unwrap_or_else.rs:17:13 - | -LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` - -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead - --> $DIR/result_map_unwrap_or_else.rs:18:13 - | -LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` - -error: aborting due to 3 previous errors - diff --git a/tests/ui/reversed_empty_ranges_fixable.fixed b/tests/ui/reversed_empty_ranges_fixable.fixed new file mode 100644 index 0000000000000..ee2cbc3cf540e --- /dev/null +++ b/tests/ui/reversed_empty_ranges_fixable.fixed @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::reversed_empty_ranges)] + +const ANSWER: i32 = 42; + +fn main() { + (21..=42).rev().for_each(|x| println!("{}", x)); + let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::>(); + + for _ in (-42..=-21).rev() {} + for _ in (21u32..42u32).rev() {} + + // These should be ignored as they are not empty ranges: + + (21..=42).for_each(|x| println!("{}", x)); + (21..42).for_each(|x| println!("{}", x)); + + let arr = [1, 2, 3, 4, 5]; + let _ = &arr[1..=3]; + let _ = &arr[1..3]; + + for _ in 21..=42 {} + for _ in 21..42 {} +} diff --git a/tests/ui/reversed_empty_ranges_fixable.rs b/tests/ui/reversed_empty_ranges_fixable.rs new file mode 100644 index 0000000000000..6ed5ca6daa0e8 --- /dev/null +++ b/tests/ui/reversed_empty_ranges_fixable.rs @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::reversed_empty_ranges)] + +const ANSWER: i32 = 42; + +fn main() { + (42..=21).for_each(|x| println!("{}", x)); + let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); + + for _ in -21..=-42 {} + for _ in 42u32..21u32 {} + + // These should be ignored as they are not empty ranges: + + (21..=42).for_each(|x| println!("{}", x)); + (21..42).for_each(|x| println!("{}", x)); + + let arr = [1, 2, 3, 4, 5]; + let _ = &arr[1..=3]; + let _ = &arr[1..3]; + + for _ in 21..=42 {} + for _ in 21..42 {} +} diff --git a/tests/ui/reversed_empty_ranges_fixable.stderr b/tests/ui/reversed_empty_ranges_fixable.stderr new file mode 100644 index 0000000000000..97933b8ff8515 --- /dev/null +++ b/tests/ui/reversed_empty_ranges_fixable.stderr @@ -0,0 +1,47 @@ +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_fixable.rs:7:5 + | +LL | (42..=21).for_each(|x| println!("{}", x)); + | ^^^^^^^^^ + | + = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | (21..=42).rev().for_each(|x| println!("{}", x)); + | ^^^^^^^^^^^^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_fixable.rs:8:13 + | +LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); + | ^^^^^^^^^^^^ + | +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::>(); + | ^^^^^^^^^^^^^^^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_fixable.rs:10:14 + | +LL | for _ in -21..=-42 {} + | ^^^^^^^^^ + | +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | for _ in (-42..=-21).rev() {} + | ^^^^^^^^^^^^^^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_fixable.rs:11:14 + | +LL | for _ in 42u32..21u32 {} + | ^^^^^^^^^^^^ + | +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | for _ in (21u32..42u32).rev() {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.fixed b/tests/ui/reversed_empty_ranges_loops_fixable.fixed new file mode 100644 index 0000000000000..f1503ed6d12f9 --- /dev/null +++ b/tests/ui/reversed_empty_ranges_loops_fixable.fixed @@ -0,0 +1,57 @@ +// run-rustfix +#![warn(clippy::reversed_empty_ranges)] + +fn main() { + const MAX_LEN: usize = 42; + + for i in (0..10).rev() { + println!("{}", i); + } + + for i in (0..=10).rev() { + println!("{}", i); + } + + for i in (0..MAX_LEN).rev() { + println!("{}", i); + } + + for i in 5..=5 { + // not an error, this is the range with only one element “5” + println!("{}", i); + } + + for i in 0..10 { + // not an error, the start index is less than the end index + println!("{}", i); + } + + for i in -10..0 { + // not an error + println!("{}", i); + } + + for i in (0..10).rev().map(|x| x * 2) { + println!("{}", i); + } + + // testing that the empty range lint folds constants + for i in (5 + 4..10).rev() { + println!("{}", i); + } + + for i in ((3 - 1)..(5 + 2)).rev() { + println!("{}", i); + } + + for i in (2 * 2)..(2 * 3) { + // no error, 4..6 is fine + println!("{}", i); + } + + let x = 42; + for i in x..10 { + // no error, not constant-foldable + println!("{}", i); + } +} diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.rs b/tests/ui/reversed_empty_ranges_loops_fixable.rs new file mode 100644 index 0000000000000..a733788dc22c1 --- /dev/null +++ b/tests/ui/reversed_empty_ranges_loops_fixable.rs @@ -0,0 +1,57 @@ +// run-rustfix +#![warn(clippy::reversed_empty_ranges)] + +fn main() { + const MAX_LEN: usize = 42; + + for i in 10..0 { + println!("{}", i); + } + + for i in 10..=0 { + println!("{}", i); + } + + for i in MAX_LEN..0 { + println!("{}", i); + } + + for i in 5..=5 { + // not an error, this is the range with only one element “5” + println!("{}", i); + } + + for i in 0..10 { + // not an error, the start index is less than the end index + println!("{}", i); + } + + for i in -10..0 { + // not an error + println!("{}", i); + } + + for i in (10..0).map(|x| x * 2) { + println!("{}", i); + } + + // testing that the empty range lint folds constants + for i in 10..5 + 4 { + println!("{}", i); + } + + for i in (5 + 2)..(3 - 1) { + println!("{}", i); + } + + for i in (2 * 2)..(2 * 3) { + // no error, 4..6 is fine + println!("{}", i); + } + + let x = 42; + for i in x..10 { + // no error, not constant-foldable + println!("{}", i); + } +} diff --git a/tests/ui/reversed_empty_ranges_loops_fixable.stderr b/tests/ui/reversed_empty_ranges_loops_fixable.stderr new file mode 100644 index 0000000000000..e89e040a0ff9e --- /dev/null +++ b/tests/ui/reversed_empty_ranges_loops_fixable.stderr @@ -0,0 +1,69 @@ +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_loops_fixable.rs:7:14 + | +LL | for i in 10..0 { + | ^^^^^ + | + = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | for i in (0..10).rev() { + | ^^^^^^^^^^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_loops_fixable.rs:11:14 + | +LL | for i in 10..=0 { + | ^^^^^^ + | +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | for i in (0..=10).rev() { + | ^^^^^^^^^^^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_loops_fixable.rs:15:14 + | +LL | for i in MAX_LEN..0 { + | ^^^^^^^^^^ + | +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | for i in (0..MAX_LEN).rev() { + | ^^^^^^^^^^^^^^^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_loops_fixable.rs:34:14 + | +LL | for i in (10..0).map(|x| x * 2) { + | ^^^^^^^ + | +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | for i in (0..10).rev().map(|x| x * 2) { + | ^^^^^^^^^^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_loops_fixable.rs:39:14 + | +LL | for i in 10..5 + 4 { + | ^^^^^^^^^ + | +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | for i in (5 + 4..10).rev() { + | ^^^^^^^^^^^^^^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_loops_fixable.rs:43:14 + | +LL | for i in (5 + 2)..(3 - 1) { + | ^^^^^^^^^^^^^^^^ + | +help: consider using the following if you are attempting to iterate over this range in reverse + | +LL | for i in ((3 - 1)..(5 + 2)).rev() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/reversed_empty_ranges_loops_unfixable.rs b/tests/ui/reversed_empty_ranges_loops_unfixable.rs new file mode 100644 index 0000000000000..c4c572244168b --- /dev/null +++ b/tests/ui/reversed_empty_ranges_loops_unfixable.rs @@ -0,0 +1,11 @@ +#![warn(clippy::reversed_empty_ranges)] + +fn main() { + for i in 5..5 { + println!("{}", i); + } + + for i in (5 + 2)..(8 - 1) { + println!("{}", i); + } +} diff --git a/tests/ui/reversed_empty_ranges_loops_unfixable.stderr b/tests/ui/reversed_empty_ranges_loops_unfixable.stderr new file mode 100644 index 0000000000000..30095d20cfd41 --- /dev/null +++ b/tests/ui/reversed_empty_ranges_loops_unfixable.stderr @@ -0,0 +1,16 @@ +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_loops_unfixable.rs:4:14 + | +LL | for i in 5..5 { + | ^^^^ + | + = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_loops_unfixable.rs:8:14 + | +LL | for i in (5 + 2)..(8 - 1) { + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/reversed_empty_ranges_unfixable.rs b/tests/ui/reversed_empty_ranges_unfixable.rs new file mode 100644 index 0000000000000..c9ca4c4766831 --- /dev/null +++ b/tests/ui/reversed_empty_ranges_unfixable.rs @@ -0,0 +1,15 @@ +#![warn(clippy::reversed_empty_ranges)] + +const ANSWER: i32 = 42; +const SOME_NUM: usize = 3; + +fn main() { + let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21); + + let arr = [1, 2, 3, 4, 5]; + let _ = &arr[3usize..=1usize]; + let _ = &arr[SOME_NUM..1]; + let _ = &arr[3..3]; + + for _ in ANSWER..ANSWER {} +} diff --git a/tests/ui/reversed_empty_ranges_unfixable.stderr b/tests/ui/reversed_empty_ranges_unfixable.stderr new file mode 100644 index 0000000000000..12e5483ecdfff --- /dev/null +++ b/tests/ui/reversed_empty_ranges_unfixable.stderr @@ -0,0 +1,34 @@ +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_unfixable.rs:7:13 + | +LL | let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21); + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings` + +error: this range is reversed and using it to index a slice will panic at run-time + --> $DIR/reversed_empty_ranges_unfixable.rs:10:18 + | +LL | let _ = &arr[3usize..=1usize]; + | ^^^^^^^^^^^^^^^ + +error: this range is reversed and using it to index a slice will panic at run-time + --> $DIR/reversed_empty_ranges_unfixable.rs:11:18 + | +LL | let _ = &arr[SOME_NUM..1]; + | ^^^^^^^^^^^ + +error: this range is empty and using it to index a slice will always yield an empty slice + --> $DIR/reversed_empty_ranges_unfixable.rs:12:18 + | +LL | let _ = &arr[3..3]; + | ^^^^ + +error: this range is empty so it will yield no values + --> $DIR/reversed_empty_ranges_unfixable.rs:14:14 + | +LL | for _ in ANSWER..ANSWER {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/unused_unit.fixed b/tests/ui/unused_unit.fixed index 3f63624720f75..07f2791786d7f 100644 --- a/tests/ui/unused_unit.fixed +++ b/tests/ui/unused_unit.fixed @@ -14,11 +14,10 @@ struct Unitter; impl Unitter { - // try to disorient the lint with multiple unit returns and newlines #[allow(clippy::no_effect)] - pub fn get_unit (), G>(&self, f: F, _g: G) - where G: Fn() -> () { - let _y: &dyn Fn() -> () = &f; + pub fn get_unit(&self, f: F, _g: G) + where G: Fn() { + let _y: &dyn Fn() = &f; (); // this should not lint, as it's not in return type position } } @@ -30,6 +29,20 @@ impl Into<()> for Unitter { } } +trait Trait { + fn redundant(&self, _f: F, _g: G, _h: H) + where + G: FnMut() , + H: Fn() ; +} + +impl Trait for Unitter { + fn redundant(&self, _f: F, _g: G, _h: H) + where + G: FnMut() , + H: Fn() {} +} + fn return_unit() { } #[allow(clippy::needless_return)] diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs index 8fc072ebd69f8..e2c6afb020f58 100644 --- a/tests/ui/unused_unit.rs +++ b/tests/ui/unused_unit.rs @@ -14,10 +14,8 @@ struct Unitter; impl Unitter { - // try to disorient the lint with multiple unit returns and newlines #[allow(clippy::no_effect)] - pub fn get_unit (), G>(&self, f: F, _g: G) -> - () + pub fn get_unit (), G>(&self, f: F, _g: G) -> () where G: Fn() -> () { let _y: &dyn Fn() -> () = &f; (); // this should not lint, as it's not in return type position @@ -31,6 +29,20 @@ impl Into<()> for Unitter { } } +trait Trait { + fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + where + G: FnMut() -> (), + H: Fn() -> (); +} + +impl Trait for Unitter { + fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + where + G: FnMut() -> (), + H: Fn() -> () {} +} + fn return_unit() -> () { () } #[allow(clippy::needless_return)] diff --git a/tests/ui/unused_unit.stderr b/tests/ui/unused_unit.stderr index a013d2b3495ba..81e6738e6bf67 100644 --- a/tests/ui/unused_unit.stderr +++ b/tests/ui/unused_unit.stderr @@ -1,10 +1,8 @@ error: unneeded unit return type - --> $DIR/unused_unit.rs:19:59 + --> $DIR/unused_unit.rs:18:29 | -LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> - | ___________________________________________________________^ -LL | | () - | |__________^ help: remove the `-> ()` +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^ help: remove the `-> ()` | note: the lint level is defined here --> $DIR/unused_unit.rs:12:9 @@ -13,40 +11,94 @@ LL | #![deny(clippy::unused_unit)] | ^^^^^^^^^^^^^^^^^^^ error: unneeded unit return type - --> $DIR/unused_unit.rs:29:19 + --> $DIR/unused_unit.rs:19:19 + | +LL | where G: Fn() -> () { + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:18:59 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:20:27 + | +LL | let _y: &dyn Fn() -> () = &f; + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:27:19 | LL | fn into(self) -> () { | ^^^^^ help: remove the `-> ()` error: unneeded unit expression - --> $DIR/unused_unit.rs:30:9 + --> $DIR/unused_unit.rs:28:9 | LL | () | ^^ help: remove the final `()` error: unneeded unit return type - --> $DIR/unused_unit.rs:34:18 + --> $DIR/unused_unit.rs:33:30 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:35:20 + | +LL | G: FnMut() -> (), + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:36:17 + | +LL | H: Fn() -> (); + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:40:30 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:42:20 + | +LL | G: FnMut() -> (), + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:43:17 + | +LL | H: Fn() -> () {} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:46:18 | LL | fn return_unit() -> () { () } | ^^^^^ help: remove the `-> ()` error: unneeded unit expression - --> $DIR/unused_unit.rs:34:26 + --> $DIR/unused_unit.rs:46:26 | LL | fn return_unit() -> () { () } | ^^ help: remove the final `()` error: unneeded `()` - --> $DIR/unused_unit.rs:44:14 + --> $DIR/unused_unit.rs:56:14 | LL | break(); | ^^ help: remove the `()` error: unneeded `()` - --> $DIR/unused_unit.rs:46:11 + --> $DIR/unused_unit.rs:58:11 | LL | return(); | ^^ help: remove the `()` -error: aborting due to 7 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/unwrap.rs b/tests/ui/unwrap.rs index fcd1fcd14d48f..a4a3cd1d37977 100644 --- a/tests/ui/unwrap.rs +++ b/tests/ui/unwrap.rs @@ -1,4 +1,4 @@ -#![warn(clippy::option_unwrap_used, clippy::result_unwrap_used)] +#![warn(clippy::unwrap_used)] fn unwrap_option() { let opt = Some(0); diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr index b90ce68fa97ac..4f0858005f6e7 100644 --- a/tests/ui/unwrap.stderr +++ b/tests/ui/unwrap.stderr @@ -4,7 +4,7 @@ error: used `unwrap()` on `an Option` value LL | let _ = opt.unwrap(); | ^^^^^^^^^^^^ | - = note: `-D clippy::option-unwrap-used` implied by `-D warnings` + = note: `-D clippy::unwrap-used` implied by `-D warnings` = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: used `unwrap()` on `a Result` value @@ -13,7 +13,6 @@ error: used `unwrap()` on `a Result` value LL | let _ = res.unwrap(); | ^^^^^^^^^^^^ | - = note: `-D clippy::result-unwrap-used` implied by `-D warnings` = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message error: aborting due to 2 previous errors diff --git a/tests/ui/identity_conversion.fixed b/tests/ui/useless_conversion.fixed similarity index 93% rename from tests/ui/identity_conversion.fixed rename to tests/ui/useless_conversion.fixed index dd3fc56e98bcf..fdd4bc581f305 100644 --- a/tests/ui/identity_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![deny(clippy::identity_conversion)] +#![deny(clippy::useless_conversion)] fn test_generic(val: T) -> T { let _ = val; @@ -41,7 +41,7 @@ fn main() { let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); - #[allow(clippy::identity_conversion)] + #[allow(clippy::useless_conversion)] { let _: String = "foo".into(); let _ = String::from("foo"); diff --git a/tests/ui/identity_conversion.rs b/tests/ui/useless_conversion.rs similarity index 94% rename from tests/ui/identity_conversion.rs rename to tests/ui/useless_conversion.rs index 875ed7db373b6..4cae745e7c021 100644 --- a/tests/ui/identity_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,6 +1,6 @@ // run-rustfix -#![deny(clippy::identity_conversion)] +#![deny(clippy::useless_conversion)] fn test_generic(val: T) -> T { let _ = T::from(val); @@ -41,7 +41,7 @@ fn main() { let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); - #[allow(clippy::identity_conversion)] + #[allow(clippy::useless_conversion)] { let _: String = "foo".into(); let _ = String::from("foo"); diff --git a/tests/ui/identity_conversion.stderr b/tests/ui/useless_conversion.stderr similarity index 67% rename from tests/ui/identity_conversion.stderr rename to tests/ui/useless_conversion.stderr index 57626b23795cf..7df3507edfd9e 100644 --- a/tests/ui/identity_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,65 +1,65 @@ -error: identical conversion - --> $DIR/identity_conversion.rs:6:13 +error: useless conversion + --> $DIR/useless_conversion.rs:6:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` | note: the lint level is defined here - --> $DIR/identity_conversion.rs:3:9 + --> $DIR/useless_conversion.rs:3:9 | -LL | #![deny(clippy::identity_conversion)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::useless_conversion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: identical conversion - --> $DIR/identity_conversion.rs:7:5 +error: useless conversion + --> $DIR/useless_conversion.rs:7:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` -error: identical conversion - --> $DIR/identity_conversion.rs:19:22 +error: useless conversion + --> $DIR/useless_conversion.rs:19:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` -error: identical conversion - --> $DIR/identity_conversion.rs:51:21 +error: useless conversion + --> $DIR/useless_conversion.rs:51:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` -error: identical conversion - --> $DIR/identity_conversion.rs:52:21 +error: useless conversion + --> $DIR/useless_conversion.rs:52:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` -error: identical conversion - --> $DIR/identity_conversion.rs:53:13 +error: useless conversion + --> $DIR/useless_conversion.rs:53:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` -error: identical conversion - --> $DIR/identity_conversion.rs:54:13 +error: useless conversion + --> $DIR/useless_conversion.rs:54:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` -error: identical conversion - --> $DIR/identity_conversion.rs:55:13 +error: useless conversion + --> $DIR/useless_conversion.rs:55:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` -error: identical conversion - --> $DIR/identity_conversion.rs:56:13 +error: useless conversion + --> $DIR/useless_conversion.rs:56:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` -error: identical conversion - --> $DIR/identity_conversion.rs:57:21 +error: useless conversion + --> $DIR/useless_conversion.rs:57:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` From b6844489f9dc3ca7aa23c3111a4576099919d65f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 May 2020 18:28:12 -0400 Subject: [PATCH 046/695] Emit a better diagnostic when function actually has a 'self' parameter Fixes #66898 When we are unable to resolve a reference to `self`, we current assume that the containing function doesn't have a `self` parameter, and emit an error message accordingly. However, if the reference to `self` was created by a macro invocation, then resolution will correctly fail, due to hygiene. In this case, we don't want to tell the user that the containing fuction doesn't have a 'self' paramter if it actually has one. This PR checks for the precense of a 'self' parameter, and adjusts the error message we emit accordingly. TODO: The exact error message we emit could probably be improved. Should we explicitly mention hygiene? --- src/librustc_resolve/late.rs | 5 +++-- src/librustc_resolve/late/diagnostics.rs | 11 ++++++++-- src/test/ui/hygiene/missing-self-diag.rs | 23 ++++++++++++++++++++ src/test/ui/hygiene/missing-self-diag.stderr | 17 +++++++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/hygiene/missing-self-diag.rs create mode 100644 src/test/ui/hygiene/missing-self-diag.stderr diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index e541920e89ed4..477e3be5cc2f8 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -347,7 +347,7 @@ struct DiagnosticMetadata<'ast> { currently_processing_generics: bool, /// The current enclosing function (used for better errors). - current_function: Option, + current_function: Option<(FnKind<'ast>, Span)>, /// A list of labels as of yet unused. Labels will be removed from this map when /// they are used (in a `break` or `continue` statement) @@ -466,7 +466,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind, FnKind::Fn(FnCtxt::Assoc(_), ..) | FnKind::Closure(..) => NormalRibKind, }; - let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp)); + let previous_value = + replace(&mut self.diagnostic_metadata.current_function, Some((fn_kind, sp))); debug!("(resolving function) entering function"); let declaration = fn_kind.decl(); diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index dc92b465c2bc1..b1a1f8725a180 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -195,8 +195,15 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { _ => "`self` value is a keyword only available in methods with a `self` parameter" .to_string(), }); - if let Some(span) = &self.diagnostic_metadata.current_function { - err.span_label(*span, "this function doesn't have a `self` parameter"); + if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function { + // The current function has a `self' parameter, but we were unable to resolve + // a reference to `self`. This can only happen if the `self` identifier we + // are resolving came from a different hygiene context. + if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) { + err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters"); + } else { + err.span_label(*span, "this function doesn't have a `self` parameter"); + } } return (err, Vec::new()); } diff --git a/src/test/ui/hygiene/missing-self-diag.rs b/src/test/ui/hygiene/missing-self-diag.rs new file mode 100644 index 0000000000000..f934f793c7f27 --- /dev/null +++ b/src/test/ui/hygiene/missing-self-diag.rs @@ -0,0 +1,23 @@ +// Regression test for issue #66898 +// Tests that we don't emit a nonsensical error message +// when a macro invocation tries to access `self` from a function +// that has a 'self' parameter + +pub struct Foo; + +macro_rules! call_bar { + () => { + self.bar(); //~ ERROR expected value + } +} + +impl Foo { + pub fn foo(&self) { + call_bar!(); + } + + pub fn bar(&self) { + } +} + +fn main() {} diff --git a/src/test/ui/hygiene/missing-self-diag.stderr b/src/test/ui/hygiene/missing-self-diag.stderr new file mode 100644 index 0000000000000..075d6b76bb7b2 --- /dev/null +++ b/src/test/ui/hygiene/missing-self-diag.stderr @@ -0,0 +1,17 @@ +error[E0424]: expected value, found module `self` + --> $DIR/missing-self-diag.rs:10:9 + | +LL | self.bar(); + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter +... +LL | / pub fn foo(&self) { +LL | | call_bar!(); + | | ------------ in this macro invocation +LL | | } + | |_____- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0424`. From 8841ede3648b5f12284dae850ec065374fd3af46 Mon Sep 17 00:00:00 2001 From: csmoe Date: Sat, 16 May 2020 17:10:08 +0800 Subject: [PATCH 047/695] bless suggestion on spell out --- src/librustc_error_codes/error_codes.rs | 2 +- .../error_codes/{E0754.md => E0755.md} | 7 +++++-- src/librustc_typeck/check/mod.rs | 2 +- .../ui/async-await/issue-61949-self-return-type.stderr | 5 +++-- src/test/ui/async-await/issue-69276.stderr | 8 -------- src/test/ui/impl-trait/bound-normalization-fail.stderr | 5 +++-- 6 files changed, 13 insertions(+), 16 deletions(-) rename src/librustc_error_codes/error_codes/{E0754.md => E0755.md} (70%) delete mode 100644 src/test/ui/async-await/issue-69276.stderr diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 52d40fd0f2fa1..6467561e509fa 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -435,7 +435,7 @@ E0750: include_str!("./error_codes/E0750.md"), E0751: include_str!("./error_codes/E0751.md"), E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), -E0754: include_str!("./error_codes/E0754.md"), +E0755: include_str!("./error_codes/E0755.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0754.md b/src/librustc_error_codes/error_codes/E0755.md similarity index 70% rename from src/librustc_error_codes/error_codes/E0754.md rename to src/librustc_error_codes/error_codes/E0755.md index e7cea98201003..b6eb2e34ccfc5 100644 --- a/src/librustc_error_codes/error_codes/E0754.md +++ b/src/librustc_error_codes/error_codes/E0755.md @@ -1,4 +1,5 @@ -`async fn`/`impl trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope. +`async fn`/`impl trait` return type cannot contain a projection +or `Self` that references lifetimes from a parent scope. Erroneous code example: @@ -24,6 +25,8 @@ impl<'a> S<'a> { } ``` -This will be allowed at some point in the future, but the implementation is not yet complete. See the [issue-61949] for this limitation. +This will be allowed at some point in the future, +but the implementation is not yet complete. +See the [issue-61949] for this limitation. [issue-61949]: https://github.com/rust-lang/rust/issues/61949 diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0906c25baef09..bd8f628957dc1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1701,7 +1701,7 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, let mut err = struct_span_err!( tcx.sess, span, - E0754, + E0755, "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ a parent scope", if is_async { "async fn" } else { "impl Trait" }, diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr index 12fb77d8dd637..fe05754c83ff8 100644 --- a/src/test/ui/async-await/issue-61949-self-return-type.stderr +++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr @@ -1,8 +1,9 @@ -error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope +error[E0755]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope --> $DIR/issue-61949-self-return-type.rs:11:40 | LL | pub async fn new(_bar: &'a i32) -> Self { - | ^^^^ + | ^^^^ help: consider spelling out the type instead: `Foo<'a>` error: aborting due to previous error +For more information about this error, try `rustc --explain E0754`. diff --git a/src/test/ui/async-await/issue-69276.stderr b/src/test/ui/async-await/issue-69276.stderr deleted file mode 100644 index 1ebfdfa8b54c5..0000000000000 --- a/src/test/ui/async-await/issue-69276.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope - --> $DIR/issue-69276.rs:6:33 - | -LL | async fn new(i: &'a i32) -> Self { - | ^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr index f5092044627f6..04b398f5b5283 100644 --- a/src/test/ui/impl-trait/bound-normalization-fail.stderr +++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr @@ -20,7 +20,7 @@ help: consider constraining the associated type `::Assoc LL | fn foo_fail>() -> impl FooLike { | ^^^^^^^^^^^^ -error: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope +error[E0755]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope --> $DIR/bound-normalization-fail.rs:43:41 | LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike { @@ -42,4 +42,5 @@ LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike Date: Sun, 17 May 2020 22:21:02 -0500 Subject: [PATCH 048/695] Add to the list of words clippy::doc_markdown ignores --- clippy_lints/src/utils/conf.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 57b9eafd14dbd..9e8e0ff30ec6b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -120,10 +120,12 @@ define_Conf! { "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", - "JavaScript", + "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", - "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap", + "OCaml", + "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", + "TensorFlow", "TrueType", "iOS", "macOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", From d25b25610b1ced7dda9c61c3ee7f6281be247bd7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 6 May 2020 15:03:53 +0100 Subject: [PATCH 049/695] Handle InlineAsm in clippy --- clippy_lints/src/loops.rs | 18 ++++++++-- clippy_lints/src/utils/author.rs | 4 +++ clippy_lints/src/utils/hir_utils.rs | 55 +++++++++++++++++++++++++++-- clippy_lints/src/utils/inspector.rs | 27 +++++++++++++- clippy_lints/src/utils/sugg.rs | 2 ++ clippy_lints/src/write.rs | 5 +-- 6 files changed, 104 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 84e8a010738cf..38a5829b3f745 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -16,8 +16,8 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor}; use rustc_hir::{ - def_id, BinOpKind, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, GenericArg, HirId, LoopSource, - MatchSource, Mutability, Node, Pat, PatKind, QPath, Stmt, StmtKind, + def_id, BinOpKind, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, GenericArg, HirId, InlineAsmOperand, + LoopSource, MatchSource, Mutability, Node, Pat, PatKind, QPath, Stmt, StmtKind, }; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -693,6 +693,20 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { NeverLoopResult::AlwaysBreak } }, + ExprKind::InlineAsm(ref asm) => asm + .operands + .iter() + .map(|o| match o { + InlineAsmOperand::In { expr, .. } + | InlineAsmOperand::InOut { expr, .. } + | InlineAsmOperand::Const { expr } + | InlineAsmOperand::Sym { expr } => never_loop_expr(expr, main_loop_id), + InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id), + InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { + never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id) + }, + }) + .fold(NeverLoopResult::Otherwise, combine_both), ExprKind::Struct(_, _, None) | ExprKind::Yield(_, _) | ExprKind::Closure(_, _, _, _, _) diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 74601008dca41..bbcf396eef7d6 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -469,6 +469,10 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { println!("Ret(None) = {};", current); } }, + ExprKind::InlineAsm(_) => { + println!("InlineAsm(_) = {};", current); + println!(" // unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment"); + }, ExprKind::LlvmInlineAsm(_) => { println!("LlvmInlineAsm(_) = {};", current); println!(" // unimplemented: `ExprKind::LlvmInlineAsm` is not further destructured at the moment"); diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index bd7da57c665dc..92c27e79452ab 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -1,10 +1,11 @@ use crate::consts::{constant_context, constant_simple}; use crate::utils::differing_macro_contexts; +use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::{ BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FnRetTy, GenericArg, - GenericArgs, Guard, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, - TyKind, TypeBinding, + GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path, PathSegment, QPath, + Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lint::LateContext; use rustc_middle::ich::StableHashingContextProvider; @@ -474,6 +475,56 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(a); self.hash_expr(i); }, + ExprKind::InlineAsm(ref asm) => { + for piece in asm.template { + match piece { + InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s), + InlineAsmTemplatePiece::Placeholder { + operand_idx, + modifier, + span: _, + } => { + operand_idx.hash(&mut self.s); + modifier.hash(&mut self.s); + }, + } + } + asm.options.hash(&mut self.s); + for op in asm.operands { + match op { + InlineAsmOperand::In { reg, expr } => { + reg.hash(&mut self.s); + self.hash_expr(expr); + }, + InlineAsmOperand::Out { reg, late, expr } => { + reg.hash(&mut self.s); + late.hash(&mut self.s); + if let Some(expr) = expr { + self.hash_expr(expr); + } + }, + InlineAsmOperand::InOut { reg, late, expr } => { + reg.hash(&mut self.s); + late.hash(&mut self.s); + self.hash_expr(expr); + }, + InlineAsmOperand::SplitInOut { + reg, + late, + in_expr, + out_expr, + } => { + reg.hash(&mut self.s); + late.hash(&mut self.s); + self.hash_expr(in_expr); + if let Some(out_expr) = out_expr { + self.hash_expr(out_expr); + } + }, + InlineAsmOperand::Const { expr } | InlineAsmOperand::Sym { expr } => self.hash_expr(expr), + } + } + }, ExprKind::LlvmInlineAsm(..) | ExprKind::Err => {}, ExprKind::Lit(ref l) => { l.node.hash(&mut self.s); diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 7e8c61ba24a22..748c11fac64ff 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -1,7 +1,7 @@ //! checks for attributes use crate::utils::get_attr; -use rustc_ast::ast::Attribute; +use rustc_ast::ast::{Attribute, InlineAsmTemplatePiece}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::Session; @@ -282,6 +282,31 @@ fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, indent: usize) { print_expr(cx, e, indent + 1); } }, + hir::ExprKind::InlineAsm(ref asm) => { + println!("{}InlineAsm", ind); + println!("{}template: {}", ind, InlineAsmTemplatePiece::to_string(asm.template)); + println!("{}options: {:?}", ind, asm.options); + println!("{}operands:", ind); + for op in asm.operands { + match op { + hir::InlineAsmOperand::In { expr, .. } => print_expr(cx, expr, indent + 1), + hir::InlineAsmOperand::Out { expr, .. } => { + if let Some(expr) = expr { + print_expr(cx, expr, indent + 1); + } + }, + hir::InlineAsmOperand::InOut { expr, .. } => print_expr(cx, expr, indent + 1), + hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { + print_expr(cx, in_expr, indent + 1); + if let Some(out_expr) = out_expr { + print_expr(cx, out_expr, indent + 1); + } + }, + hir::InlineAsmOperand::Const { expr } => print_expr(cx, expr, indent + 1), + hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1), + } + } + }, hir::ExprKind::LlvmInlineAsm(ref asm) => { let inputs = &asm.inputs_exprs; let outputs = &asm.outputs_exprs; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index a8fe637d3d978..4ebe2e2852fb4 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -108,6 +108,7 @@ impl<'a> Sugg<'a> { | hir::ExprKind::Call(..) | hir::ExprKind::Field(..) | hir::ExprKind::Index(..) + | hir::ExprKind::InlineAsm(..) | hir::ExprKind::LlvmInlineAsm(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Loop(..) @@ -150,6 +151,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Field(..) | ast::ExprKind::ForLoop(..) | ast::ExprKind::Index(..) + | ast::ExprKind::InlineAsm(..) | ast::ExprKind::LlvmInlineAsm(..) | ast::ExprKind::Lit(..) | ast::ExprKind::Loop(..) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 26bf463bd2922..dfa6223f1b9dd 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -353,7 +353,8 @@ impl Write { is_write: bool, ) -> (Option, Option) { use fmt_macros::{ - AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, Parser, Piece, + AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, ParseMode, Parser, + Piece, }; let tts = tts.clone(); @@ -376,7 +377,7 @@ impl Write { }; let tmp = fmtstr.symbol.as_str(); let mut args = vec![]; - let mut fmt_parser = Parser::new(&tmp, None, Vec::new(), false); + let mut fmt_parser = Parser::new(&tmp, None, None, false, ParseMode::Format); while let Some(piece) = fmt_parser.next() { if !fmt_parser.errors.is_empty() { return (None, expr); From 1d7a731f3dfc416d761963cf1bbb0abee9764665 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 18 May 2020 15:16:23 +0100 Subject: [PATCH 050/695] Stabilize AtomicN::fetch_min and AtomicN::fetch_max --- src/libcore/sync/atomic.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 220f221cdd36d..1af287df04ee3 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1882,7 +1882,6 @@ using [`Release`] makes the load part [`Relaxed`]. # Examples ``` -#![feature(atomic_min_max)] ", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; let foo = ", stringify!($atomic_type), "::new(23); @@ -1893,7 +1892,6 @@ assert_eq!(foo.load(Ordering::SeqCst), 42); If you want to obtain the maximum value in one step, you can use the following: ``` -#![feature(atomic_min_max)] ", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; let foo = ", stringify!($atomic_type), "::new(23); @@ -1902,9 +1900,7 @@ let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar); assert!(max_foo == 42); ```"), #[inline] - #[unstable(feature = "atomic_min_max", - reason = "easier and faster min/max than writing manual CAS loop", - issue = "48655")] + #[stable(feature = "atomic_min_max", since = "1.45.0")] #[$cfg_cas] pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. @@ -1933,7 +1929,6 @@ using [`Release`] makes the load part [`Relaxed`]. # Examples ``` -#![feature(atomic_min_max)] ", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; let foo = ", stringify!($atomic_type), "::new(23); @@ -1946,7 +1941,6 @@ assert_eq!(foo.load(Ordering::Relaxed), 22); If you want to obtain the minimum value in one step, you can use the following: ``` -#![feature(atomic_min_max)] ", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; let foo = ", stringify!($atomic_type), "::new(23); @@ -1955,9 +1949,7 @@ let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar); assert_eq!(min_foo, 12); ```"), #[inline] - #[unstable(feature = "atomic_min_max", - reason = "easier and faster min/max than writing manual CAS loop", - issue = "48655")] + #[stable(feature = "atomic_min_max", since = "1.45.0")] #[$cfg_cas] pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type { // SAFETY: data races are prevented by atomic intrinsics. From cc91041f26fa90920cc96c13c431610153a61586 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 18 May 2020 08:00:44 -0700 Subject: [PATCH 051/695] Always generated object code for `#![no_builtins]` This commit updates the code generation for `#![no_builtins]` to always produce object files instead of conditionally respecting `-Clinker-plugin-lto` and sometimes producing bitcode. This is intended to address rust-lang/cargo#8239. The issue at hand here is that Cargo has tried to get "smarter" about codegen in whole crate graph scenarios. When LTO is enabled it attempts to avoid codegen on as many crates as possible, opting to pass `-Clinker-plugin-lto` where it can to only generate bitcode. When this is combined with `-Zbuild-std`, however, it means that `compiler-builtins` only generates LLVM bitcode instead of object files. Rustc's own LTO passes then explicitly skip `compiler-builtins` (because it wouldn't work anyway) which means that LLVM bitcode gets sent to the linker, which chokes most of the time. The fix in this PR is to not actually respect `-Clinker-plugin-lto` for `#![no_builtins]` crates. These crates, even if slurped up by the linker rather than rustc, will not work with LTO. They define symbols which are only referenced as part of codegen, so LTO's aggressive internalization would trivially remove the symbols only to have the linker realize later that the symbol is undefined. Since pure-bitcode never makes sense for these libraries, the `-Clinker-plugin-lto` flag is silently ignored. --- src/librustc_codegen_ssa/back/write.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 53dfe7cb74998..f9ee7d8c5de71 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -142,8 +142,22 @@ impl ModuleConfig { let emit_obj = if !should_emit_obj { EmitObj::None } else if sess.target.target.options.obj_is_bitcode - || sess.opts.cg.linker_plugin_lto.enabled() + || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins) { + // This case is selected if the target uses objects as bitcode, or + // if linker plugin LTO is enabled. In the linker plugin LTO case + // the assumption is that the final link-step will read the bitcode + // and convert it to object code. This may be done by either the + // native linker or rustc itself. + // + // Note, however, that the linker-plugin-lto requested here is + // explicitly ignored for `#![no_builtins]` crates. These crates are + // specifically ignored by rustc's LTO passes and wouldn't work if + // loaded into the linker. These crates define symbols that LLVM + // lowers intrinsics to, and these symbol dependencies aren't known + // until after codegen. As a result any crate marked + // `#![no_builtins]` is assumed to not participate in LTO and + // instead goes on to generate object code. EmitObj::Bitcode } else if need_bitcode_in_object(sess) { EmitObj::ObjectCode(BitcodeSection::Full) From 49d5f5a977a1c0e0dffc8e189cef1977476f5253 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Wed, 6 May 2020 07:43:18 +0200 Subject: [PATCH 052/695] Add `len` and `slice_from_raw_parts` to `NonNull<[T]>` This follows the precedent of the recently-added `<*const [T]>::len` (adding to its tracking issue https://github.com/rust-lang/rust/issues/71146) and `ptr::slice_from_raw_parts`. --- src/libcore/lib.rs | 2 ++ src/libcore/ptr/non_null.rs | 59 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 3b7929f00168a..ca13433caec8d 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -87,6 +87,8 @@ #![feature(const_generics)] #![feature(const_ptr_offset_from)] #![feature(const_result)] +#![feature(const_slice_from_raw_parts)] +#![feature(const_slice_ptr_len)] #![feature(const_type_name)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs index 7d08503215ed0..ed99452397f9c 100644 --- a/src/libcore/ptr/non_null.rs +++ b/src/libcore/ptr/non_null.rs @@ -142,6 +142,65 @@ impl NonNull { } } +impl NonNull<[T]> { + /// Create a non-null raw slice from a thin pointer and a length. + /// + /// The `len` argument is the number of **elements**, not the number of bytes. + /// + /// This function is safe, but dereferencing the return value is unsafe. + /// See the documentation of [`slice::from_raw_parts`] for slice safety requirements. + /// + /// [`slice::from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html + /// + /// # Examples + /// + /// ```rust + /// #![feature(nonnull_slice_from_raw_parts)] + /// + /// use std::ptr::NonNull; + /// + /// // create a slice pointer when starting out with a pointer to the first element + /// let mut x = [5, 6, 7]; + /// let nonnull_pointer = NonNull::new(x.as_mut_ptr()).unwrap(); + /// let slice = NonNull::slice_from_raw_parts(nonnull_pointer, 3); + /// assert_eq!(unsafe { slice.as_ref()[2] }, 7); + /// ``` + /// + /// (Note that this example artifically demonstrates a use of this method, + /// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.) + #[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")] + #[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")] + #[inline] + pub const fn slice_from_raw_parts(data: NonNull, size: usize) -> Self { + // SAFETY: `data` is a `NonNull` pointer which is necessarily non-null + unsafe { Self::new_unchecked(super::slice_from_raw_parts_mut(data.as_ptr(), size)) } + } + + /// Return the length and a non-null raw slice. + /// + /// The returned value is the number of **elements**, not the number of bytes. + /// + /// This function is safe, even when the non-null raw slice cannot be dereferenced to a slice + /// because the pointer does not have a valid address. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_len, nonnull_slice_from_raw_parts)] + /// + /// use std::ptr::NonNull; + /// + /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); + /// assert_eq!(slice.len(), 3); + /// ``` + #[unstable(feature = "slice_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + #[inline] + pub const fn len(self) -> usize { + self.as_ptr().len() + } +} + #[stable(feature = "nonnull", since = "1.25.0")] impl Clone for NonNull { #[inline] From 861dfaa855ba61bdc8eaccc0652e6fdb8eadf4c3 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 7 May 2020 07:47:24 +0200 Subject: [PATCH 053/695] Apply suggestions from code review Co-authored-by: kennytm --- src/libcore/ptr/non_null.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs index ed99452397f9c..870364a61dd47 100644 --- a/src/libcore/ptr/non_null.rs +++ b/src/libcore/ptr/non_null.rs @@ -143,7 +143,7 @@ impl NonNull { } impl NonNull<[T]> { - /// Create a non-null raw slice from a thin pointer and a length. + /// Creates a non-null raw slice from a thin pointer and a length. /// /// The `len` argument is the number of **elements**, not the number of bytes. /// @@ -171,12 +171,12 @@ impl NonNull<[T]> { #[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")] #[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")] #[inline] - pub const fn slice_from_raw_parts(data: NonNull, size: usize) -> Self { + pub const fn slice_from_raw_parts(data: NonNull, len: usize) -> Self { // SAFETY: `data` is a `NonNull` pointer which is necessarily non-null - unsafe { Self::new_unchecked(super::slice_from_raw_parts_mut(data.as_ptr(), size)) } + unsafe { Self::new_unchecked(super::slice_from_raw_parts_mut(data.as_ptr(), len)) } } - /// Return the length and a non-null raw slice. + /// Returns the length of a non-null raw slice. /// /// The returned value is the number of **elements**, not the number of bytes. /// From 56c494a1487e7fdea07c641e5a182cffba1d15c0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 19 May 2020 13:20:33 +0200 Subject: [PATCH 054/695] Clean up E0593 explanation --- src/librustc_error_codes/error_codes/E0593.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc_error_codes/error_codes/E0593.md b/src/librustc_error_codes/error_codes/E0593.md index b32923a9e5ff9..1902d73f4d00c 100644 --- a/src/librustc_error_codes/error_codes/E0593.md +++ b/src/librustc_error_codes/error_codes/E0593.md @@ -11,3 +11,14 @@ fn main() { foo(|y| { }); } ``` + +You have to provide the same number of arguments as expected by the `Fn`-based +type. So to fix the previous example, we need to remove the `y` argument: + +``` +fn foo(x: F) { } + +fn main() { + foo(|| { }); // ok! +} +``` From fc4c9a6c7f27dc4cc68d8b2afe77e88a29ff8a31 Mon Sep 17 00:00:00 2001 From: Tymoteusz Jankowski Date: Tue, 19 May 2020 13:54:22 +0200 Subject: [PATCH 055/695] Make intra-link resolve links for both trait and impl items --- .../passes/collect_intra_doc_links.rs | 61 +++++++++++-------- src/test/rustdoc/issue-72340.rs | 19 ++++++ 2 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 src/test/rustdoc/issue-72340.rs diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a3ef350a0487e..05f3b598ecdf4 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -232,37 +232,46 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did, ) => { - // We need item's parent to know if it's - // trait impl or struct/enum/etc impl - let item_parent = item_opt + // Checks if item_name belongs to `impl SomeItem` + let impl_item = cx + .tcx + .inherent_impls(did) + .iter() + .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) + .find(|item| item.ident.name == item_name); + let trait_item = item_opt .and_then(|item| self.cx.as_local_hir_id(item.def_id)) .and_then(|item_hir| { + // Checks if item_name belongs to `impl SomeTrait for SomeItem` let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir); - self.cx.tcx.hir().find(parent_hir) + let item_parent = self.cx.tcx.hir().find(parent_hir); + match item_parent { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. }, + .. + })) => cx + .tcx + .associated_item_def_ids(self_ty.hir_id.owner) + .iter() + .map(|child| { + let associated_item = cx.tcx.associated_item(*child); + associated_item + }) + .find(|child| child.ident.name == item_name), + _ => None, + } }); - let item = match item_parent { - Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. }, - .. - })) => { - // trait impl - cx.tcx - .associated_item_def_ids(self_ty.hir_id.owner) - .iter() - .map(|child| { - let associated_item = cx.tcx.associated_item(*child); - associated_item - }) - .find(|child| child.ident.name == item_name) - } - _ => { - // struct/enum/etc. impl - cx.tcx - .inherent_impls(did) - .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) - .find(|item| item.ident.name == item_name) + let item = match (impl_item, trait_item) { + (Some(from_impl), Some(_)) => { + // Although it's ambiguous, return impl version for compat. sake. + // To handle that properly resolve() would have to support + // something like + // [`ambi_fn`](::ambi_fn) + Some(from_impl) } + (None, Some(from_trait)) => Some(from_trait), + (Some(from_impl), None) => Some(from_impl), + _ => None, }; if let Some(item) = item { diff --git a/src/test/rustdoc/issue-72340.rs b/src/test/rustdoc/issue-72340.rs new file mode 100644 index 0000000000000..6ed3bfbe3e54b --- /dev/null +++ b/src/test/rustdoc/issue-72340.rs @@ -0,0 +1,19 @@ +#![crate_name = "foo"] + +pub struct Body; + +impl Body { + pub fn empty() -> Self { + Body + } + +} + +impl Default for Body { + // @has foo/struct.Body.html '//a/@href' '../foo/struct.Body.html#method.empty' + + /// Returns [`Body::empty()`](Body::empty). + fn default() -> Body { + Body::empty() + } +} From 842dd072612a5a53bef37f242f8f2be8896902cc Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 19 May 2020 15:18:16 +0200 Subject: [PATCH 056/695] Add note that a subtree fix and stack limit increase is required --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6697ff2f40d46..c6a3998ec4ec1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -209,6 +209,13 @@ You can then sync with the remote names from above, e.g.: $ git subtree push -P src/tools/clippy clippy-local sync-from-rust ``` +_Note:_ The first time running `git subtree push` a cache has to be built. This +involves going through the complete Clippy history once. For this you have to +increase the stack limit though, which you can do with `ulimit -s 60000`. For +this to work, you will need the fix of `git subtree` available +[here][gitgitgadget-pr]. + +[gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 [subtree]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust From 1a9ba3b2c208f8131587ece3ad8fb159336dd694 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 19 May 2020 16:36:14 +0200 Subject: [PATCH 057/695] Add note, that a merge commit after push is necessary --- CONTRIBUTING.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c6a3998ec4ec1..c9180e58fc251 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -178,6 +178,15 @@ to be run inside the `rust` directory): _Note:_ This will directly push to the remote repository. You can also push to your local copy by replacing the remote address with `/path/to/rust-clippy` directory. + + _Note:_ Most of the time you have to create a merge commit in the + `rust-clippy` repo (this has to be done in the Clippy repo, not in the + rust-copy of Clippy): + ```bash + git checkout sync-from-rust + git fetch upstream + git merge upstream/master + ``` 3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to accelerate the process ping the `@rust-lang/clippy` team in your PR and/or ~~annoy~~ ask them in the [Discord] channel.) From 2bf6833d37ddf043c68c9234a787a7455ee56ab5 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 19 May 2020 13:08:50 -0400 Subject: [PATCH 058/695] Remove dangling COPYRIGHT references Missed in 2a663555ddf36f6b041445894a8c175cd1bc718c. --- .../issue-49851/compiler-builtins-error.rs | 2 -- src/test/ui/ui-testing-optout.rs | 3 --- src/test/ui/ui-testing-optout.stderr | 16 ++++++++-------- src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs | 4 ---- .../ui/unsafe/unsafe-fn-assign-deref-ptr.stderr | 2 +- 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/test/ui/issues/issue-49851/compiler-builtins-error.rs b/src/test/ui/issues/issue-49851/compiler-builtins-error.rs index 3484ff3b87432..9449376513fd5 100644 --- a/src/test/ui/issues/issue-49851/compiler-builtins-error.rs +++ b/src/test/ui/issues/issue-49851/compiler-builtins-error.rs @@ -1,6 +1,4 @@ //~ ERROR 1:1: 1:1: can't find crate for `core` [E0463] -// http://rust-lang.org/COPYRIGHT. -// // compile-flags: --target thumbv7em-none-eabihf #![deny(unsafe_code)] diff --git a/src/test/ui/ui-testing-optout.rs b/src/test/ui/ui-testing-optout.rs index 901263c5bf8d2..88e811583161c 100644 --- a/src/test/ui/ui-testing-optout.rs +++ b/src/test/ui/ui-testing-optout.rs @@ -3,9 +3,6 @@ // Line number < 10 type A = B; //~ ERROR -// http://rust-lang.org/COPYRIGHT. -// - // Line number >=10, <100 type C = D; //~ ERROR diff --git a/src/test/ui/ui-testing-optout.stderr b/src/test/ui/ui-testing-optout.stderr index ff5bf6238e20b..f562bb74c1173 100644 --- a/src/test/ui/ui-testing-optout.stderr +++ b/src/test/ui/ui-testing-optout.stderr @@ -8,21 +8,21 @@ error[E0412]: cannot find type `B` in this scope | similarly named type alias `A` defined here error[E0412]: cannot find type `D` in this scope - --> $DIR/ui-testing-optout.rs:10:10 - | -4 | type A = B; - | ----------- similarly named type alias `A` defined here + --> $DIR/ui-testing-optout.rs:7:10 + | +4 | type A = B; + | ----------- similarly named type alias `A` defined here ... -10 | type C = D; - | ^ help: a type alias with a similar name exists: `A` +7 | type C = D; + | ^ help: a type alias with a similar name exists: `A` error[E0412]: cannot find type `F` in this scope - --> $DIR/ui-testing-optout.rs:95:10 + --> $DIR/ui-testing-optout.rs:92:10 | 4 | type A = B; | ----------- similarly named type alias `A` defined here ... -95 | type E = F; +92 | type E = F; | ^ help: a type alias with a similar name exists: `A` error: aborting due to 3 previous errors diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs index 64bdca5245719..91264e790c8db 100644 --- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs @@ -1,7 +1,3 @@ -// http://rust-lang.org/COPYRIGHT. -// - - fn f(p: *mut u8) { *p = 0; //~ ERROR dereference of raw pointer is unsafe return; diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr index 8f621d6ed11ca..28db83db92ac8 100644 --- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/unsafe-fn-assign-deref-ptr.rs:6:5 + --> $DIR/unsafe-fn-assign-deref-ptr.rs:2:5 | LL | *p = 0; | ^^^^^^ dereference of raw pointer From 9b2b8a5afa833795b66267684615497c9547878d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 May 2020 15:51:01 -0400 Subject: [PATCH 059/695] Break tokens before checking if they are 'probably equal' Fixes #68489 When checking two `TokenStreams` to see if they are 'probably equal', we ignore the `IsJoint` information associated with each `TokenTree`. However, the `IsJoint` information determines whether adjacent tokens will be 'glued' (if possible) when construction the `TokenStream` - e.g. `[Gt Gt]` can be 'glued' to `BinOp(Shr)`. Since we are ignoring the `IsJoint` information, 'glued' and 'unglued' tokens are equivalent for determining if two `TokenStreams` are 'probably equal'. Therefore, we need to 'unglue' all tokens in the stream to avoid false negatives (which cause us to throw out the cached tokens, losing span information). --- src/librustc_ast/tokenstream.rs | 34 +++++++++++++++++-- src/test/ui/proc-macro/turbo-proc-macro.rs | 9 +++++ .../ui/proc-macro/turbo-proc-macro.stderr | 9 +++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/proc-macro/turbo-proc-macro.rs create mode 100644 src/test/ui/proc-macro/turbo-proc-macro.stderr diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index 916a5ff6f46f4..38483360c0664 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -338,8 +338,38 @@ impl TokenStream { true } - let mut t1 = self.trees().filter(semantic_tree); - let mut t2 = other.trees().filter(semantic_tree); + // When comparing two `TokenStream`s, we ignore the `IsJoint` information. + // + // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will + // use `Token.glue` on adjacent tokens with the proper `IsJoint`. + // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`) + // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent + // when determining if two `TokenStream`s are 'probably equal'. + // + // Therefore, we use `break_two_token_op` to convert all tokens + // to the 'unglued' form (if it exists). This ensures that two + // `TokenStream`s which differ only in how their tokens are glued + // will be considered 'probably equal', which allows us to keep spans. + // + // This is important when the original `TokenStream` contained + // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces + // will be omitted when we pretty-print, which can cause the original + // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`, + // leading to some tokens being 'glued' together in one stream but not + // the other. See #68489 for more details. + fn break_tokens(tree: TokenTree) -> impl Iterator { + if let TokenTree::Token(token) = &tree { + if let Some((first, second)) = token.kind.break_two_token_op() { + return SmallVec::from_buf([TokenTree::Token(Token::new(first, DUMMY_SP)), TokenTree::Token(Token::new(second, DUMMY_SP))]).into_iter() + } + } + let mut vec = SmallVec::<[_; 2]>::new(); + vec.push(tree); + vec.into_iter() + } + + let mut t1 = self.trees().filter(semantic_tree).flat_map(break_tokens); + let mut t2 = other.trees().filter(semantic_tree).flat_map(break_tokens); for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { if !t1.probably_equal_for_proc_macro(&t2) { return false; diff --git a/src/test/ui/proc-macro/turbo-proc-macro.rs b/src/test/ui/proc-macro/turbo-proc-macro.rs new file mode 100644 index 0000000000000..a255955f38da0 --- /dev/null +++ b/src/test/ui/proc-macro/turbo-proc-macro.rs @@ -0,0 +1,9 @@ +// aux-build:test-macros.rs + +extern crate test_macros; + +#[test_macros::recollect_attr] +fn repro() { + f :: < Vec < _ > > ( ) ; //~ ERROR cannot find +} +fn main() {} diff --git a/src/test/ui/proc-macro/turbo-proc-macro.stderr b/src/test/ui/proc-macro/turbo-proc-macro.stderr new file mode 100644 index 0000000000000..85c93b9345c37 --- /dev/null +++ b/src/test/ui/proc-macro/turbo-proc-macro.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find function `f` in this scope + --> $DIR/turbo-proc-macro.rs:7:5 + | +LL | f :: < Vec < _ > > ( ) ; + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. From 4a8ccdcc0b518e3c1878ce0be888fd85521b2026 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 May 2020 19:45:58 -0400 Subject: [PATCH 060/695] Use a fixed-point iteration when breaking tokens Some tokens need to be broken in a loop until we reach 'unbreakable' tokens. --- src/librustc_ast/tokenstream.rs | 45 ++++++++++++++++--- src/test/ui/proc-macro/break-token-spans.rs | 16 +++++++ .../ui/proc-macro/break-token-spans.stderr | 21 +++++++++ src/test/ui/proc-macro/turbo-proc-macro.rs | 9 ---- .../ui/proc-macro/turbo-proc-macro.stderr | 9 ---- 5 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 src/test/ui/proc-macro/break-token-spans.rs create mode 100644 src/test/ui/proc-macro/break-token-spans.stderr delete mode 100644 src/test/ui/proc-macro/turbo-proc-macro.rs delete mode 100644 src/test/ui/proc-macro/turbo-proc-macro.stderr diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index 38483360c0664..075aaa7e5bc01 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -21,6 +21,8 @@ use rustc_macros::HashStable_Generic; use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; +use log::debug; + use std::{iter, mem}; /// When the main rust parser encounters a syntax-extension invocation, it @@ -358,14 +360,47 @@ impl TokenStream { // leading to some tokens being 'glued' together in one stream but not // the other. See #68489 for more details. fn break_tokens(tree: TokenTree) -> impl Iterator { + // In almost all cases, we should have either zero or one levels + // of 'unglueing'. However, in some unusual cases, we may need + // to iterate breaking tokens mutliple times. For example: + // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]' + let mut token_trees: SmallVec<[_; 2]>; if let TokenTree::Token(token) = &tree { - if let Some((first, second)) = token.kind.break_two_token_op() { - return SmallVec::from_buf([TokenTree::Token(Token::new(first, DUMMY_SP)), TokenTree::Token(Token::new(second, DUMMY_SP))]).into_iter() + let mut out = SmallVec::<[_; 2]>::new(); + out.push(token.clone()); + // Iterate to fixpoint: + // * We start off with 'out' containing our initial token, and `temp` empty + // * If we are able to break any tokens in `out`, then `out` will have + // at least one more element than 'temp', so we will try to break tokens + // again. + // * If we cannot break any tokens in 'out', we are done + loop { + let mut temp = SmallVec::<[_; 2]>::new(); + let mut changed = false; + + for token in out.into_iter() { + if let Some((first, second)) = token.kind.break_two_token_op() { + temp.push(Token::new(first, DUMMY_SP)); + temp.push(Token::new(second, DUMMY_SP)); + changed = true; + } else { + temp.push(token); + } + } + out = temp; + if !changed { + break; + } + } + token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect(); + if token_trees.len() != 1 { + debug!("break_tokens: broke {:?} to {:?}", tree, token_trees); } + } else { + token_trees = SmallVec::new(); + token_trees.push(tree); } - let mut vec = SmallVec::<[_; 2]>::new(); - vec.push(tree); - vec.into_iter() + token_trees.into_iter() } let mut t1 = self.trees().filter(semantic_tree).flat_map(break_tokens); diff --git a/src/test/ui/proc-macro/break-token-spans.rs b/src/test/ui/proc-macro/break-token-spans.rs new file mode 100644 index 0000000000000..ce8b9ebb4f9d2 --- /dev/null +++ b/src/test/ui/proc-macro/break-token-spans.rs @@ -0,0 +1,16 @@ +// aux-build:test-macros.rs +// Regression test for issues #68489 and #70987 +// Tests that we properly break tokens in `probably_equal_for_proc_macro` +// See #72306 +// +// Note that the weird spacing in this example is critical +// for testing the issue. + +extern crate test_macros; + +#[test_macros::recollect_attr] +fn repro() { + f :: < Vec < _ > > ( ) ; //~ ERROR cannot find + let a: Option>= true; //~ ERROR mismatched +} +fn main() {} diff --git a/src/test/ui/proc-macro/break-token-spans.stderr b/src/test/ui/proc-macro/break-token-spans.stderr new file mode 100644 index 0000000000000..caca973f252f7 --- /dev/null +++ b/src/test/ui/proc-macro/break-token-spans.stderr @@ -0,0 +1,21 @@ +error[E0425]: cannot find function `f` in this scope + --> $DIR/break-token-spans.rs:13:5 + | +LL | f :: < Vec < _ > > ( ) ; + | ^ not found in this scope + +error[E0308]: mismatched types + --> $DIR/break-token-spans.rs:14:32 + | +LL | let a: Option>= true; + | ------------------ ^^^^ expected enum `std::option::Option`, found `bool` + | | + | expected due to this + | + = note: expected enum `std::option::Option>` + found type `bool` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0425. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/proc-macro/turbo-proc-macro.rs b/src/test/ui/proc-macro/turbo-proc-macro.rs deleted file mode 100644 index a255955f38da0..0000000000000 --- a/src/test/ui/proc-macro/turbo-proc-macro.rs +++ /dev/null @@ -1,9 +0,0 @@ -// aux-build:test-macros.rs - -extern crate test_macros; - -#[test_macros::recollect_attr] -fn repro() { - f :: < Vec < _ > > ( ) ; //~ ERROR cannot find -} -fn main() {} diff --git a/src/test/ui/proc-macro/turbo-proc-macro.stderr b/src/test/ui/proc-macro/turbo-proc-macro.stderr deleted file mode 100644 index 85c93b9345c37..0000000000000 --- a/src/test/ui/proc-macro/turbo-proc-macro.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0425]: cannot find function `f` in this scope - --> $DIR/turbo-proc-macro.rs:7:5 - | -LL | f :: < Vec < _ > > ( ) ; - | ^ not found in this scope - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0425`. From daea09cf91fdf50c03500784d0f1612db42afd2b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 4 May 2020 14:03:59 -0700 Subject: [PATCH 061/695] Add `MaybeInitializedLocals` dataflow analysis --- .../dataflow/impls/init_locals.rs | 115 ++++++++++++++++++ src/librustc_mir/dataflow/impls/mod.rs | 2 + 2 files changed, 117 insertions(+) create mode 100644 src/librustc_mir/dataflow/impls/init_locals.rs diff --git a/src/librustc_mir/dataflow/impls/init_locals.rs b/src/librustc_mir/dataflow/impls/init_locals.rs new file mode 100644 index 0000000000000..01cb794a2e085 --- /dev/null +++ b/src/librustc_mir/dataflow/impls/init_locals.rs @@ -0,0 +1,115 @@ +//! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals. +//! +//! A local will be maybe initialized if *any* projections of that local might be initialized. + +use crate::dataflow::{self, BottomValue, GenKill}; + +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{self, BasicBlock, Local, Location}; + +pub struct MaybeInitializedLocals; + +impl BottomValue for MaybeInitializedLocals { + /// bottom = uninit + const BOTTOM_VALUE: bool = false; +} + +impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { + type Idx = Local; + + const NAME: &'static str = "maybe_init_locals"; + + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { + body.local_decls.len() + } + + fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut BitSet) { + // Function arguments are initialized to begin with. + for arg in body.args_iter() { + entry_set.insert(arg); + } + } +} + +impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals { + fn statement_effect( + &self, + trans: &mut impl GenKill, + statement: &mir::Statement<'tcx>, + loc: Location, + ) { + TransferFunction { trans }.visit_statement(statement, loc) + } + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + TransferFunction { trans }.visit_terminator(terminator, loc) + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + return_place: mir::Place<'tcx>, + ) { + trans.gen(return_place.local) + } + + /// See `Analysis::apply_yield_resume_effect`. + fn yield_resume_effect( + &self, + trans: &mut impl GenKill, + _resume_block: BasicBlock, + resume_place: mir::Place<'tcx>, + ) { + trans.gen(resume_place.local) + } +} + +struct TransferFunction<'a, T> { + trans: &'a mut T, +} + +impl Visitor<'tcx> for TransferFunction<'a, T> +where + T: GenKill, +{ + fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { + use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext}; + match context { + // These are handled specially in `call_return_effect` and `yield_resume_effect`. + PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {} + + // Otherwise, when a place is mutated, we must consider it possibly initialized. + PlaceContext::MutatingUse(_) => self.trans.gen(local), + + // If the local is moved out of, or if it gets marked `StorageDead`, consider it no + // longer initialized. + PlaceContext::NonUse(NonUseContext::StorageDead) + | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => self.trans.kill(local), + + // All other uses do not affect this analysis. + PlaceContext::NonUse( + NonUseContext::StorageLive + | NonUseContext::AscribeUserTy + | NonUseContext::VarDebugInfo, + ) + | PlaceContext::NonMutatingUse( + NonMutatingUseContext::Inspect + | NonMutatingUseContext::Copy + | NonMutatingUseContext::SharedBorrow + | NonMutatingUseContext::ShallowBorrow + | NonMutatingUseContext::UniqueBorrow + | NonMutatingUseContext::AddressOf + | NonMutatingUseContext::Projection, + ) => {} + } + } +} diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index e199a174efbc3..d5def0389126a 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -22,11 +22,13 @@ use crate::dataflow::drop_flag_effects; mod borrowed_locals; pub(super) mod borrows; +mod init_locals; mod liveness; mod storage_liveness; pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; pub use self::borrows::Borrows; +pub use self::init_locals::MaybeInitializedLocals; pub use self::liveness::MaybeLiveLocals; pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; From fc964c5317f52e6ca7d8e62cc976d2b920a32a15 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 6 May 2020 11:38:59 -0700 Subject: [PATCH 062/695] Clean up generator live locals analysis Instead of using a bespoke dataflow analysis, `MaybeRequiresStorage`, for computing locals that need to be stored across yield points and that have conflicting storage, use a combination of simple, generally applicable dataflow analyses. In this case, the formula for locals that are live at a yield point is: live_across_yield := (live & init) | (!movable & borrowed) and the formula for locals that require storage (and thus may conflict with others) at a given point is: requires_storage := init | borrowed `init` is `MaybeInitializedLocals`, a direct equivalent of `MaybeInitializedPlaces` that works only on whole `Local`s. `borrowed` and `live` are the pre-existing `MaybeBorrowedLocals` and `MaybeLiveLocals` analyses respectively. --- src/librustc_mir/transform/generator.rs | 250 +++++++++++------------- 1 file changed, 113 insertions(+), 137 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 4bf2adcd450c0..60d2e865d6b83 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -50,7 +50,7 @@ //! Otherwise it drops all the values in scope at the last suspension point. use crate::dataflow::impls::{ - MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, + MaybeBorrowedLocals, MaybeInitializedLocals, MaybeLiveLocals, MaybeStorageLive, }; use crate::dataflow::{self, Analysis}; use crate::transform::no_landing_pads::no_landing_pads; @@ -444,86 +444,74 @@ fn locals_live_across_suspend_points( movable: bool, ) -> LivenessInfo { let def_id = source.def_id(); - let body_ref: &Body<'_> = &body; // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. let mut storage_live = MaybeStorageLive::new(always_live_locals.clone()) - .into_engine(tcx, body_ref, def_id) + .into_engine(tcx, body, def_id) .iterate_to_fixpoint() - .into_results_cursor(body_ref); - - // Calculate the MIR locals which have been previously - // borrowed (even if they are still active). - let borrowed_locals_results = - MaybeBorrowedLocals::all_borrows().into_engine(tcx, body_ref, def_id).iterate_to_fixpoint(); - - let mut borrowed_locals_cursor = - dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results); - - // Calculate the MIR locals that we actually need to keep storage around - // for. - let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results) - .into_engine(tcx, body_ref, def_id) - .iterate_to_fixpoint(); - let mut requires_storage_cursor = - dataflow::ResultsCursor::new(body_ref, &requires_storage_results); - - // Calculate the liveness of MIR locals ignoring borrows. - let mut liveness = MaybeLiveLocals - .into_engine(tcx, body_ref, def_id) + .into_results_cursor(body); + + let mut init = MaybeInitializedLocals + .into_engine(tcx, body, def_id) .iterate_to_fixpoint() - .into_results_cursor(body_ref); + .into_results_cursor(body); - let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks()); - let mut live_locals_at_suspension_points = Vec::new(); - let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len()); + let mut live = MaybeLiveLocals + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); - for (block, data) in body.basic_blocks().iter_enumerated() { - if let TerminatorKind::Yield { .. } = data.terminator().kind { - let loc = Location { block, statement_index: data.statements.len() }; - - liveness.seek_to_block_end(block); - let mut live_locals = liveness.get().clone(); - - if !movable { - // The `liveness` variable contains the liveness of MIR locals ignoring borrows. - // This is correct for movable generators since borrows cannot live across - // suspension points. However for immovable generators we need to account for - // borrows, so we conseratively assume that all borrowed locals are live until - // we find a StorageDead statement referencing the locals. - // To do this we just union our `liveness` result with `borrowed_locals`, which - // contains all the locals which has been borrowed before this suspension point. - // If a borrow is converted to a raw reference, we must also assume that it lives - // forever. Note that the final liveness is still bounded by the storage liveness - // of the local, which happens using the `intersect` operation below. - borrowed_locals_cursor.seek_before_primary_effect(loc); - live_locals.union(borrowed_locals_cursor.get()); - } + let mut borrowed = MaybeBorrowedLocals::all_borrows() + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); - // Store the storage liveness for later use so we can restore the state - // after a suspension point - storage_live.seek_before_primary_effect(loc); - storage_liveness_map[block] = Some(storage_live.get().clone()); + // Liveness across yield points is determined by the following boolean equation, where `live`, + // `init` and `borrowed` come from dataflow and `movable` is a property of the generator. + // Movable generators do not allow borrows to live across yield points, so they don't need to + // store a local simply because it is borrowed. + // + // live_across_yield := (live & init) | (!movable & borrowed) + // + let mut locals_live_across_yield_point = |block| { + live.seek_to_block_end(block); + let mut live_locals = live.get().clone(); - // Locals live are live at this point only if they are used across - // suspension points (the `liveness` variable) - // and their storage is required (the `storage_required` variable) - requires_storage_cursor.seek_before_primary_effect(loc); - live_locals.intersect(requires_storage_cursor.get()); + init.seek_to_block_end(block); + live_locals.intersect(init.get()); - // The generator argument is ignored. - live_locals.remove(SELF_ARG); + if !movable { + borrowed.seek_to_block_end(block); + live_locals.union(borrowed.get()); + } - debug!("loc = {:?}, live_locals = {:?}", loc, live_locals); + live_locals + }; - // Add the locals live at this suspension point to the set of locals which live across - // any suspension points - live_locals_at_any_suspension_point.union(&live_locals); + let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks()); + let mut live_locals_at_suspension_points = Vec::new(); + let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len()); - live_locals_at_suspension_points.push(live_locals); + for (block, data) in body.basic_blocks().iter_enumerated() { + if !matches!(data.terminator().kind, TerminatorKind::Yield { .. }) { + continue; } + + // Store the storage liveness for later use so we can restore the state + // after a suspension point + storage_live.seek_to_block_end(block); + storage_liveness_map[block] = Some(storage_live.get().clone()); + + let mut live_locals = locals_live_across_yield_point(block); + + // Ignore the generator's `self` argument since it is handled seperately. + live_locals.remove(SELF_ARG); + debug!("block = {:?}, live_locals = {:?}", block, live_locals); + live_locals_at_any_suspension_point.union(&live_locals); + live_locals_at_suspension_points.push(live_locals); } + debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point); // Renumber our liveness_map bitsets to include only the locals we are @@ -534,10 +522,11 @@ fn locals_live_across_suspend_points( .collect(); let storage_conflicts = compute_storage_conflicts( - body_ref, + body, &live_locals_at_any_suspension_point, always_live_locals.clone(), - requires_storage_results, + init, + borrowed, ); LivenessInfo { @@ -569,6 +558,33 @@ fn renumber_bitset( out } +/// Record conflicts between locals at the current dataflow cursor positions. +/// +/// You need to seek the cursors before calling this function. +fn record_conflicts_at_curr_loc( + local_conflicts: &mut BitMatrix, + init: &dataflow::ResultsCursor<'mir, 'tcx, MaybeInitializedLocals>, + borrowed: &dataflow::ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>, +) { + // A local requires storage if it is initialized or borrowed. For now, a local + // becomes uninitialized if it is moved from, but is still considered "borrowed". + // + // requires_storage := init | borrowed + // + // FIXME: This function is called in a loop, so it might be better to pass in a temporary + // bitset rather than cloning here. + let mut requires_storage = init.get().clone(); + requires_storage.union(borrowed.get()); + + for local in requires_storage.iter() { + local_conflicts.union_row_with(&requires_storage, local); + } + + if requires_storage.count() > 1 { + trace!("requires_storage={:?}", requires_storage); + } +} + /// For every saved local, looks for which locals are StorageLive at the same /// time. Generates a bitset for every local of all the other locals that may be /// StorageLive simultaneously with that local. This is used in the layout @@ -577,30 +593,40 @@ fn compute_storage_conflicts( body: &'mir Body<'tcx>, stored_locals: &BitSet, always_live_locals: storage::AlwaysLiveLocals, - requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, + mut init: dataflow::ResultsCursor<'mir, 'tcx, MaybeInitializedLocals>, + mut borrowed: dataflow::ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>, ) -> BitMatrix { - assert_eq!(body.local_decls.len(), stored_locals.domain_size()); - debug!("compute_storage_conflicts({:?})", body.span); - debug!("always_live = {:?}", always_live_locals); - - // Locals that are always live or ones that need to be stored across - // suspension points are not eligible for overlap. - let mut ineligible_locals = always_live_locals.into_inner(); - ineligible_locals.intersect(stored_locals); + assert_eq!(body.local_decls.len(), stored_locals.domain_size()); - // Compute the storage conflicts for all eligible locals. - let mut visitor = StorageConflictVisitor { - body, - stored_locals: &stored_locals, - local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), - }; + // Locals that are always live conflict with all other locals. + // + // FIXME: Why do we need to handle locals without `Storage{Live,Dead}` specially here? + // Shouldn't it be enough to know whether they are initialized? + let always_live_locals = always_live_locals.into_inner(); + let mut local_conflicts = BitMatrix::from_row_n(&always_live_locals, body.local_decls.len()); + + // Visit every reachable statement and terminator. The exact order does not matter. When two + // locals are live at the same point in time, add an entry in the conflict matrix. + for (block, data) in traversal::preorder(body) { + // Ignore unreachable blocks. + if data.terminator().kind == TerminatorKind::Unreachable { + continue; + } - // Visit only reachable basic blocks. The exact order is not important. - let reachable_blocks = traversal::preorder(body).map(|(bb, _)| bb); - requires_storage.visit_with(body, reachable_blocks, &mut visitor); + for (statement_index, _) in data.statements.iter().enumerate() { + let loc = Location { block, statement_index }; + trace!("record conflicts at {:?}", loc); + init.seek_before_primary_effect(loc); + borrowed.seek_before_primary_effect(loc); + record_conflicts_at_curr_loc(&mut local_conflicts, &init, &borrowed); + } - let local_conflicts = visitor.local_conflicts; + trace!("record conflicts at end of {:?}", block); + init.seek_to_block_end(block); + borrowed.seek_to_block_end(block); + record_conflicts_at_curr_loc(&mut local_conflicts, &init, &borrowed); + } // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal). // @@ -612,7 +638,7 @@ fn compute_storage_conflicts( let mut storage_conflicts = BitMatrix::new(stored_locals.count(), stored_locals.count()); for (idx_a, local_a) in stored_locals.iter().enumerate() { let saved_local_a = GeneratorSavedLocal::new(idx_a); - if ineligible_locals.contains(local_a) { + if always_live_locals.contains(local_a) { // Conflicts with everything. storage_conflicts.insert_all_into_row(saved_local_a); } else { @@ -628,56 +654,6 @@ fn compute_storage_conflicts( storage_conflicts } -struct StorageConflictVisitor<'mir, 'tcx, 's> { - body: &'mir Body<'tcx>, - stored_locals: &'s BitSet, - // FIXME(tmandry): Consider using sparse bitsets here once we have good - // benchmarks for generators. - local_conflicts: BitMatrix, -} - -impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> { - type FlowState = BitSet; - - fn visit_statement_before_primary_effect( - &mut self, - state: &Self::FlowState, - _statement: &'mir Statement<'tcx>, - loc: Location, - ) { - self.apply_state(state, loc); - } - - fn visit_terminator_before_primary_effect( - &mut self, - state: &Self::FlowState, - _terminator: &'mir Terminator<'tcx>, - loc: Location, - ) { - self.apply_state(state, loc); - } -} - -impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> { - fn apply_state(&mut self, flow_state: &BitSet, loc: Location) { - // Ignore unreachable blocks. - if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable { - return; - } - - let mut eligible_storage_live = flow_state.clone(); - eligible_storage_live.intersect(&self.stored_locals); - - for local in eligible_storage_live.iter() { - self.local_conflicts.union_row_with(&eligible_storage_live, local); - } - - if eligible_storage_live.count() > 1 { - trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live); - } - } -} - fn compute_layout<'tcx>( tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, From 3508592c26055ddd0c79d1ad595f1dc7b0640162 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 6 May 2020 11:39:13 -0700 Subject: [PATCH 063/695] Update tests with new generator sizes --- src/test/ui/async-await/async-fn-size-moved-locals.rs | 2 +- src/test/ui/generator/size-moved-locals.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs index 636fafc2bc44a..000acf14a3fbc 100644 --- a/src/test/ui/async-await/async-fn-size-moved-locals.rs +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -114,5 +114,5 @@ fn main() { assert_eq!(1026, std::mem::size_of_val(&single_with_noop())); assert_eq!(3078, std::mem::size_of_val(&joined())); assert_eq!(3079, std::mem::size_of_val(&joined_with_noop())); - assert_eq!(7181, std::mem::size_of_val(&mixed_sizes())); + assert_eq!(6157, std::mem::size_of_val(&mixed_sizes())); } diff --git a/src/test/ui/generator/size-moved-locals.rs b/src/test/ui/generator/size-moved-locals.rs index 74c60d98154dd..a5786c2999eb4 100644 --- a/src/test/ui/generator/size-moved-locals.rs +++ b/src/test/ui/generator/size-moved-locals.rs @@ -72,6 +72,6 @@ fn overlap_x_and_y() -> impl Generator { fn main() { assert_eq!(1025, std::mem::size_of_val(&move_before_yield())); assert_eq!(1026, std::mem::size_of_val(&move_before_yield_with_noop())); - assert_eq!(2051, std::mem::size_of_val(&overlap_move_points())); + assert_eq!(1027, std::mem::size_of_val(&overlap_move_points())); assert_eq!(1026, std::mem::size_of_val(&overlap_x_and_y())); } From 157631b71d5b73ccf74b00b9583050f24c92f585 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 6 May 2020 11:41:24 -0700 Subject: [PATCH 064/695] Remove `MaybeRequiresStorage` --- src/librustc_mir/dataflow/impls/mod.rs | 2 +- .../dataflow/impls/storage_liveness.rs | 234 +----------------- 2 files changed, 2 insertions(+), 234 deletions(-) diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index d5def0389126a..ed01d6b01ea43 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -30,7 +30,7 @@ pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; pub use self::borrows::Borrows; pub use self::init_locals::MaybeInitializedLocals; pub use self::liveness::MaybeLiveLocals; -pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; +pub use self::storage_liveness::MaybeStorageLive; /// `MaybeInitializedPlaces` tracks all places that might be /// initialized upon reaching a particular point in the control flow diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index bbc4942030ef7..2a2be069b1ed8 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -1,11 +1,9 @@ pub use super::*; use crate::dataflow::BottomValue; -use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; +use crate::dataflow::{self, GenKill}; use crate::util::storage::AlwaysLiveLocals; -use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use std::cell::RefCell; #[derive(Clone)] pub struct MaybeStorageLive { @@ -78,233 +76,3 @@ impl BottomValue for MaybeStorageLive { /// bottom = dead const BOTTOM_VALUE: bool = false; } - -type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; - -/// Dataflow analysis that determines whether each local requires storage at a -/// given location; i.e. whether its storage can go away without being observed. -pub struct MaybeRequiresStorage<'mir, 'tcx> { - body: &'mir Body<'tcx>, - borrowed_locals: RefCell>, -} - -impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { - pub fn new( - body: &'mir Body<'tcx>, - borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>, - ) -> Self { - MaybeRequiresStorage { - body, - borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)), - } - } -} - -impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { - type Idx = Local; - - const NAME: &'static str = "requires_storage"; - - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() - } - - fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet) { - // The resume argument is live on function entry (we don't care about - // the `self` argument) - for arg in body.args_iter().skip(1) { - on_entry.insert(arg); - } - } -} - -impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { - fn before_statement_effect( - &self, - trans: &mut impl GenKill, - stmt: &mir::Statement<'tcx>, - loc: Location, - ) { - // If a place is borrowed in a statement, it needs storage for that statement. - self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc); - - match &stmt.kind { - StatementKind::StorageDead(l) => trans.kill(*l), - - // If a place is assigned to in a statement, it needs storage for that statement. - StatementKind::Assign(box (place, _)) - | StatementKind::SetDiscriminant { box place, .. } => { - trans.gen(place.local); - } - StatementKind::LlvmInlineAsm(asm) => { - for place in &*asm.outputs { - trans.gen(place.local); - } - } - - // Nothing to do for these. Match exhaustively so this fails to compile when new - // variants are added. - StatementKind::AscribeUserType(..) - | StatementKind::FakeRead(..) - | StatementKind::Nop - | StatementKind::Retag(..) - | StatementKind::StorageLive(..) => {} - } - } - - fn statement_effect( - &self, - trans: &mut impl GenKill, - _: &mir::Statement<'tcx>, - loc: Location, - ) { - // If we move from a place then only stops needing storage *after* - // that statement. - self.check_for_move(trans, loc); - } - - fn before_terminator_effect( - &self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, - loc: Location, - ) { - // If a place is borrowed in a terminator, it needs storage for that terminator. - self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc); - - match &terminator.kind { - TerminatorKind::Call { destination: Some((place, _)), .. } => { - trans.gen(place.local); - } - - // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for - // that is that a `yield` will return from the function, and `resume_arg` is written - // only when the generator is later resumed. Unlike `Call`, this doesn't require the - // place to have storage *before* the yield, only after. - TerminatorKind::Yield { .. } => {} - - TerminatorKind::InlineAsm { operands, .. } => { - for op in operands { - match op { - InlineAsmOperand::Out { place, .. } - | InlineAsmOperand::InOut { out_place: place, .. } => { - if let Some(place) = place { - trans.gen(place.local); - } - } - InlineAsmOperand::In { .. } - | InlineAsmOperand::Const { .. } - | InlineAsmOperand::SymFn { .. } - | InlineAsmOperand::SymStatic { .. } => {} - } - } - } - - // Nothing to do for these. Match exhaustively so this fails to compile when new - // variants are added. - TerminatorKind::Call { destination: None, .. } - | TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::FalseEdges { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} - } - } - - fn terminator_effect( - &self, - trans: &mut impl GenKill, - terminator: &mir::Terminator<'tcx>, - loc: Location, - ) { - match &terminator.kind { - // For call terminators the destination requires storage for the call - // and after the call returns successfully, but not after a panic. - // Since `propagate_call_unwind` doesn't exist, we have to kill the - // destination here, and then gen it again in `call_return_effect`. - TerminatorKind::Call { destination: Some((place, _)), .. } => { - trans.kill(place.local); - } - - // Nothing to do for these. Match exhaustively so this fails to compile when new - // variants are added. - TerminatorKind::Call { destination: None, .. } - | TerminatorKind::Yield { .. } - | TerminatorKind::Abort - | TerminatorKind::Assert { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::DropAndReplace { .. } - | TerminatorKind::FalseEdges { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::Goto { .. } - | TerminatorKind::InlineAsm { .. } - | TerminatorKind::Resume - | TerminatorKind::Return - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable => {} - } - - self.check_for_move(trans, loc); - } - - fn call_return_effect( - &self, - trans: &mut impl GenKill, - _block: BasicBlock, - _func: &mir::Operand<'tcx>, - _args: &[mir::Operand<'tcx>], - return_place: mir::Place<'tcx>, - ) { - trans.gen(return_place.local); - } - - fn yield_resume_effect( - &self, - trans: &mut impl GenKill, - _resume_block: BasicBlock, - resume_place: mir::Place<'tcx>, - ) { - trans.gen(resume_place.local); - } -} - -impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { - /// Kill locals that are fully moved and have not been borrowed. - fn check_for_move(&self, trans: &mut impl GenKill, loc: Location) { - let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals }; - visitor.visit_location(&self.body, loc); - } -} - -impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> { - /// bottom = dead - const BOTTOM_VALUE: bool = false; -} - -struct MoveVisitor<'a, 'mir, 'tcx, T> { - borrowed_locals: &'a RefCell>, - trans: &'a mut T, -} - -impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> -where - T: GenKill, -{ - fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { - if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { - let mut borrowed_locals = self.borrowed_locals.borrow_mut(); - borrowed_locals.seek_before_primary_effect(loc); - if !borrowed_locals.contains(*local) { - self.trans.kill(*local); - } - } - } -} From 90da274958a21e92d974a095d1dbc279d42de0c3 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 6 May 2020 12:40:25 -0700 Subject: [PATCH 065/695] Add comment explaining the extra `record_conflicts` --- src/librustc_mir/transform/generator.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 60d2e865d6b83..0d4ca6e7689a2 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -622,6 +622,10 @@ fn compute_storage_conflicts( record_conflicts_at_curr_loc(&mut local_conflicts, &init, &borrowed); } + // We need to look for conflicts at the end of the block as well, otherwise we would not + // observe the dataflow state after the terminator effect is applied. As long as neither + // `init` nor `borrowed` has a "before" effect, we will observe all possible dataflow + // states here or in the loop above. trace!("record conflicts at end of {:?}", block); init.seek_to_block_end(block); borrowed.seek_to_block_end(block); From d8e0807052b5e90b8d4d049d90b6325137244042 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 8 May 2020 10:15:04 -0700 Subject: [PATCH 066/695] Add comment for strange conditional --- src/librustc_mir/transform/generator.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 0d4ca6e7689a2..3920057d31ee1 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -580,6 +580,7 @@ fn record_conflicts_at_curr_loc( local_conflicts.union_row_with(&requires_storage, local); } + // `>1` because the `self` argument always requires storage. if requires_storage.count() > 1 { trace!("requires_storage={:?}", requires_storage); } From def207e262a6a2ea0bc4b9607e2b8a7a952d0799 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 8 May 2020 10:20:51 -0700 Subject: [PATCH 067/695] Look for storage conflicts before terminator effect --- src/librustc_mir/transform/generator.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 3920057d31ee1..bee129b8749aa 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -615,7 +615,9 @@ fn compute_storage_conflicts( continue; } - for (statement_index, _) in data.statements.iter().enumerate() { + // Observe the dataflow state *before* all possible locations (statement or terminator) in + // each basic block... + for statement_index in 0..=data.statements.len() { let loc = Location { block, statement_index }; trace!("record conflicts at {:?}", loc); init.seek_before_primary_effect(loc); @@ -623,10 +625,9 @@ fn compute_storage_conflicts( record_conflicts_at_curr_loc(&mut local_conflicts, &init, &borrowed); } - // We need to look for conflicts at the end of the block as well, otherwise we would not - // observe the dataflow state after the terminator effect is applied. As long as neither - // `init` nor `borrowed` has a "before" effect, we will observe all possible dataflow - // states here or in the loop above. + // ...and then observe the state *after* the terminator effect is applied. As long as + // neither `init` nor `borrowed` has a "before" effect, we will observe all possible + // dataflow states here or in the loop above. trace!("record conflicts at end of {:?}", block); init.seek_to_block_end(block); borrowed.seek_to_block_end(block); From dd49c6ffd1eb2ce5919b7ce8788a55ecc4fe13b5 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 13 May 2020 09:42:56 -0700 Subject: [PATCH 068/695] Document assumptions made in generator transform for analyses The generator transform needs to inspect all possible dataflow states. This can be done with half the number of bitset union operations if we can assume that the relevant analyses do not use "before" effects. --- src/librustc_mir/dataflow/impls/borrowed_locals.rs | 3 +++ src/librustc_mir/dataflow/impls/init_locals.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index f929b2ddde0ba..b61dc56407eb9 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -99,6 +99,9 @@ impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals where K: BorrowAnalysisKind<'tcx>, { + // The generator transform relies on the fact that this analysis does **not** use "before" + // effects. + fn statement_effect( &self, trans: &mut impl GenKill, diff --git a/src/librustc_mir/dataflow/impls/init_locals.rs b/src/librustc_mir/dataflow/impls/init_locals.rs index 01cb794a2e085..726330b1f035e 100644 --- a/src/librustc_mir/dataflow/impls/init_locals.rs +++ b/src/librustc_mir/dataflow/impls/init_locals.rs @@ -33,6 +33,9 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { } impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals { + // The generator transform relies on the fact that this analysis does **not** use "before" + // effects. + fn statement_effect( &self, trans: &mut impl GenKill, From 3ff93177cf7976c1db072cdcb4bc3f23e5f6b78c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 13 May 2020 09:45:00 -0700 Subject: [PATCH 069/695] Document why we don't look at storage liveness ...when determining what locals are live. A local cannot be borrowed before it is `storage_live` and `MaybeBorrowedLocals` already invalidates borrows on `StorageDead`. Likewise, a local cannot be initialized before it is marked StorageLive and is marked as uninitialized after `StorageDead`. --- src/librustc_mir/transform/generator.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index bee129b8749aa..5f8104e7934eb 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -505,6 +505,12 @@ fn locals_live_across_suspend_points( let mut live_locals = locals_live_across_yield_point(block); + // The combination of `MaybeInitializedLocals` and `MaybeBorrowedLocals` should be strictly + // more precise than `MaybeStorageLive` because they handle `StorageDead` themselves. This + // assumes that the MIR forbids locals from being initialized/borrowed before reaching + // `StorageLive`. + debug_assert!(storage_live.get().superset(&live_locals)); + // Ignore the generator's `self` argument since it is handled seperately. live_locals.remove(SELF_ARG); debug!("block = {:?}, live_locals = {:?}", block, live_locals); @@ -571,6 +577,9 @@ fn record_conflicts_at_curr_loc( // // requires_storage := init | borrowed // + // Just like when determining what locals are live at yield points, there is no need + // to look at storage liveness here, since `init | borrowed` is strictly more precise. + // // FIXME: This function is called in a loop, so it might be better to pass in a temporary // bitset rather than cloning here. let mut requires_storage = init.get().clone(); From 564ebbb0d19283894e87cd09333375aa0c84f8d9 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 20 May 2020 02:27:03 +0100 Subject: [PATCH 070/695] Use fcntl-based file lock for non-Linux unix --- src/librustc_data_structures/flock.rs | 77 +++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index d6fc552e66149..655248e0f5221 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -7,13 +7,13 @@ #![allow(non_camel_case_types)] #![allow(nonstandard_style)] +use std::fs::{File, OpenOptions}; use std::io; use std::path::Path; cfg_if! { - if #[cfg(unix)] { + if #[cfg(target_os = "linux")] { use std::os::unix::prelude::*; - use std::fs::{File, OpenOptions}; #[derive(Debug)] pub struct Lock { @@ -27,11 +27,11 @@ cfg_if! { exclusive: bool) -> io::Result { let file = OpenOptions::new() - .read(true) - .write(true) - .create(create) - .mode(libc::S_IRWXU as u32) - .open(p)?; + .read(true) + .write(true) + .create(create) + .mode(libc::S_IRWXU as u32) + .open(p)?; let mut operation = if exclusive { libc::LOCK_EX @@ -44,8 +44,7 @@ cfg_if! { let ret = unsafe { libc::flock(file.as_raw_fd(), operation) }; if ret == -1 { - let err = io::Error::last_os_error(); - Err(err) + Err(io::Error::last_os_error()) } else { Ok(Lock { _file: file }) } @@ -55,10 +54,68 @@ cfg_if! { // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by // `flock` is associated with the file descriptor and closing the file release it // automatically. + } else if #[cfg(unix)] { + use std::mem; + use std::os::unix::prelude::*; + + #[derive(Debug)] + pub struct Lock { + file: File, + } + + impl Lock { + pub fn new(p: &Path, + wait: bool, + create: bool, + exclusive: bool) + -> io::Result { + let file = OpenOptions::new() + .read(true) + .write(true) + .create(create) + .mode(libc::S_IRWXU as u32) + .open(p)?; + + let lock_type = if exclusive { + libc::F_WRLCK + } else { + libc::F_RDLCK + }; + + let mut flock: libc::flock = unsafe { mem::zeroed() }; + flock.l_type = lock_type as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + flock.l_start = 0; + flock.l_len = 0; + + let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK }; + let ret = unsafe { + libc::fcntl(file.as_raw_fd(), cmd, &flock) + }; + if ret == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(Lock { file }) + } + } + } + + impl Drop for Lock { + fn drop(&mut self) { + let mut flock: libc::flock = unsafe { mem::zeroed() }; + flock.l_type = libc::F_UNLCK as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + flock.l_start = 0; + flock.l_len = 0; + + unsafe { + libc::fcntl(self.file.as_raw_fd(), libc::F_SETLK, &flock); + } + } + } } else if #[cfg(windows)] { use std::mem; use std::os::windows::prelude::*; - use std::fs::{File, OpenOptions}; use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK}; use winapi::um::fileapi::LockFileEx; From 406852ae0d92e5dfda890fa75ac522963065f903 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 19 May 2020 20:00:29 -0400 Subject: [PATCH 071/695] Resolve overflow behavior for RangeFrom --- src/libcore/iter/range.rs | 10 +--------- src/libcore/ops/range.rs | 14 ++++++++++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index d74df82bddd9d..75cbda3466210 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -551,15 +551,7 @@ impl Iterator for ops::RangeFrom { #[inline] fn nth(&mut self, n: usize) -> Option { - // If we would jump over the maximum value, panic immediately. - // This is consistent with behavior before the Step redesign, - // even though it's inconsistent with n `next` calls. - // To get consistent behavior, change it to use `forward` instead. - // This change should go through FCP separately to the redesign, so is for now left as a - // FIXME: make this consistent - let plus_n = - Step::forward_checked(self.start.clone(), n).expect("overflow in RangeFrom::nth"); - // The final step should always be debug-checked. + let plus_n = Step::forward(self.start.clone(), n); self.start = Step::forward(plus_n.clone(), 1); Some(plus_n) } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index d4e6048579a56..d86f39c4550c8 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -151,10 +151,16 @@ impl> Range { /// /// The `RangeFrom` `start..` contains all values with `x >= start`. /// -/// *Note*: Currently, no overflow checking is done for the [`Iterator`] -/// implementation; if you use an integer range and the integer overflows, it -/// might panic in debug mode or create an endless loop in release mode. **This -/// overflow behavior might change in the future.** +/// *Note*: Overflow in the [`Iterator`] implementation (when the contained +/// data type reaches its numerical limit) is allowed to panic, wrap, or +/// saturate. This behavior is defined by the implementation of the [`Step`] +/// trait. For primitive integers, this follows the normal rules, and respects +/// the overflow checks profile (panic in debug, wrap in release). Note also +/// that overflow happens earlier than you might assume: the overflow happens +/// in the call to `next` that yields the maximum value, as the range must be +/// set to a state to yield the next value. +/// +/// [`Step`]: crate::iter::Step /// /// # Examples /// From 038523963ad884349edca1689e5b11ad4405d3ba Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 12 May 2020 22:18:55 +0200 Subject: [PATCH 072/695] exhaustively match during structural match checking --- .../hair/pattern/const_to_pat.rs | 5 ++- .../traits/structural_match.rs | 35 +++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index 28ec2ca13d5af..67e24a1333a32 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -125,7 +125,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { "trait objects cannot be used in patterns".to_string() } traits::NonStructuralMatchTy::Param => { - bug!("use of constant whose type is a parameter inside a pattern") + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTy::Foreign => { + bug!("use of a value of a foreign type inside a pattern") } }; diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index eb63505b69b41..9bd1334bc8e83 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -13,6 +13,7 @@ pub enum NonStructuralMatchTy<'tcx> { Adt(&'tcx AdtDef), Param, Dynamic, + Foreign, } /// This method traverses the structure of `ty`, trying to find an @@ -143,6 +144,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { self.found = Some(NonStructuralMatchTy::Dynamic); return true; // Stop visiting. } + ty::Foreign(_) => { + self.found = Some(NonStructuralMatchTy::Foreign); + return true; // Stop visiting + } ty::RawPtr(..) => { // structural-match ignores substructure of // `*const _`/`*mut _`, so skip `super_visit_with`. @@ -163,7 +168,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { return false; } ty::FnDef(..) | ty::FnPtr(..) => { - // types of formals and return in `fn(_) -> _` are also irrelevant; + // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` // // (But still tell caller to continue search.) @@ -176,7 +181,33 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // for empty array. return false; } - _ => { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Never + | ty::Error => { + // These primitive types are always structural match. + // + // `Never` is kind of special here, but as it is not inhabitable, this should be fine. + return false; + } + + ty::Array(..) + | ty::Slice(_) + | ty::Ref(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Tuple(..) + | ty::Projection(..) + | ty::UnnormalizedProjection(..) + | ty::Opaque(..) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) => { ty.super_visit_with(self); return false; } From ecab35b45a0d6d33beecbd11d7be50f2511cc4f0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 12 May 2020 23:35:29 +0200 Subject: [PATCH 073/695] note for `ty::Error`. --- .../traits/structural_match.rs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index 9bd1334bc8e83..da207cf7d3804 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -187,8 +187,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { | ty::Uint(_) | ty::Float(_) | ty::Str - | ty::Never - | ty::Error => { + | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. @@ -200,17 +199,25 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { | ty::Ref(..) | ty::Closure(..) | ty::Generator(..) - | ty::GeneratorWitness(..) | ty::Tuple(..) | ty::Projection(..) - | ty::UnnormalizedProjection(..) | ty::Opaque(..) - | ty::Bound(..) - | ty::Placeholder(_) - | ty::Infer(_) => { + | ty::GeneratorWitness(..) => { ty.super_visit_with(self); return false; } + | ty::Infer(_) + | ty::Placeholder(_) + | ty::UnnormalizedProjection(..) + | ty::Bound(..) => { + bug!("unexpected type during structural-match checking: {:?}", ty); + } + ty::Error => { + self.tcx().delay_span_bug(self.span, "ty::Error in structural-match check"); + // We still want to check other types after encountering an error, + // as this may still emit relevant errors. + return false; + } }; if !self.seen.insert(adt_def.did) { From 5a5017ec634cef0ff11b40dd08fdd4572d605d01 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 13 May 2020 00:40:28 +0200 Subject: [PATCH 074/695] Be more conservative concerning `structural_match` --- .../hair/pattern/const_to_pat.rs | 9 +++++ .../traits/structural_match.rs | 40 +++++++++---------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index 67e24a1333a32..9e3f75fdc078c 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -124,9 +124,18 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { traits::NonStructuralMatchTy::Dynamic => { "trait objects cannot be used in patterns".to_string() } + traits::NonStructuralMatchTy::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Generator => { + "generators cannot be used in patterns".to_string() + } traits::NonStructuralMatchTy::Param => { bug!("use of a constant whose type is a parameter inside a pattern") } + traits::NonStructuralMatchTy::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } traits::NonStructuralMatchTy::Foreign => { bug!("use of a value of a foreign type inside a pattern") } diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index da207cf7d3804..71fa46ccdedb7 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -14,6 +14,9 @@ pub enum NonStructuralMatchTy<'tcx> { Param, Dynamic, Foreign, + Opaque, + Generator, + Projection, } /// This method traverses the structure of `ty`, trying to find an @@ -148,6 +151,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { self.found = Some(NonStructuralMatchTy::Foreign); return true; // Stop visiting } + ty::Opaque(..) => { + self.found = Some(NonStructuralMatchTy::Opaque); + return true; + } + ty::Projection(..) => { + self.found = Some(NonStructuralMatchTy::Projection); + return true; + } + ty::Generator(..) | ty::GeneratorWitness(..) => { + self.found = Some(NonStructuralMatchTy::Generator); + return true; + } ty::RawPtr(..) => { // structural-match ignores substructure of // `*const _`/`*mut _`, so skip `super_visit_with`. @@ -181,39 +196,22 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // for empty array. return false; } - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Str - | ty::Never => { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. return false; } - ty::Array(..) - | ty::Slice(_) - | ty::Ref(..) - | ty::Closure(..) - | ty::Generator(..) - | ty::Tuple(..) - | ty::Projection(..) - | ty::Opaque(..) - | ty::GeneratorWitness(..) => { + ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { ty.super_visit_with(self); return false; } - | ty::Infer(_) - | ty::Placeholder(_) - | ty::UnnormalizedProjection(..) - | ty::Bound(..) => { + ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { bug!("unexpected type during structural-match checking: {:?}", ty); } ty::Error => { - self.tcx().delay_span_bug(self.span, "ty::Error in structural-match check"); + self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. return false; From ea47fdf78538e615eb7824ff5c194b6af4565b7f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 13 May 2020 11:52:22 +0200 Subject: [PATCH 075/695] comment return sites --- .../traits/structural_match.rs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index 71fa46ccdedb7..b877049fcf667 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -149,19 +149,19 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { } ty::Foreign(_) => { self.found = Some(NonStructuralMatchTy::Foreign); - return true; // Stop visiting + return true; // Stop visiting. } ty::Opaque(..) => { self.found = Some(NonStructuralMatchTy::Opaque); - return true; + return true; // Stop visiting. } ty::Projection(..) => { self.found = Some(NonStructuralMatchTy::Projection); - return true; + return true; // Stop visiting. } ty::Generator(..) | ty::GeneratorWitness(..) => { self.found = Some(NonStructuralMatchTy::Generator); - return true; + return true; // Stop visiting. } ty::RawPtr(..) => { // structural-match ignores substructure of @@ -179,14 +179,14 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // structural equality on `T` does not recur into the raw // pointer. Therefore, one can still use `C` in a pattern. - // (But still tell caller to continue search.) + // (But still tell the caller to continue search.) return false; } ty::FnDef(..) | ty::FnPtr(..) => { // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` // - // (But still tell caller to continue search.) + // (But still tell the caller to continue search.) return false; } ty::Array(_, n) @@ -194,16 +194,21 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { { // rust-lang/rust#62336: ignore type of contents // for empty array. + // + // (But still tell the caller to continue search.) return false; } ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. + // + // (But still tell the caller to continue search.) return false; } ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { + // First check all contained types and then tell the caller to continue searching. ty.super_visit_with(self); return false; } @@ -214,13 +219,15 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. + // + // So we continue searching here. return false; } }; if !self.seen.insert(adt_def.did) { debug!("Search already seen adt_def: {:?}", adt_def); - // let caller continue its search + // Let caller continue its search. return false; } From a5a4ec98e20e4b863cfb2f6c44faa15824fce9f3 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 13 May 2020 13:14:53 +0200 Subject: [PATCH 076/695] Add tests for opaque types --- .../structural-match-no-leak.rs | 20 ++++++++++++++++++ .../structural-match-no-leak.stderr | 8 +++++++ .../type-alias-impl-trait/structural-match.rs | 21 +++++++++++++++++++ .../structural-match.stderr | 8 +++++++ 4 files changed, 57 insertions(+) create mode 100644 src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs create mode 100644 src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr create mode 100644 src/test/ui/type-alias-impl-trait/structural-match.rs create mode 100644 src/test/ui/type-alias-impl-trait/structural-match.stderr diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs new file mode 100644 index 0000000000000..479d6cd9af765 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -0,0 +1,20 @@ +#![feature(const_fn, type_alias_impl_trait)] + +type Bar = impl Send; + +// While i32 is structural-match, we do not want to leak this information. +// (See https://github.com/rust-lang/rust/issues/72156) +const fn leak_free() -> Bar { + 7i32 +} +const LEAK_FREE: Bar = leak_free(); + +fn leak_free_test() { + match todo!() { + LEAK_FREE => (), + //~^ opaque types cannot be used in patterns + _ => (), + } +} + +fn main() { } diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr new file mode 100644 index 0000000000000..ae0d8e8d4239c --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr @@ -0,0 +1,8 @@ +error: opaque types cannot be used in patterns + --> $DIR/structural-match-no-leak.rs:14:9 + | +LL | LEAK_FREE => (), + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs new file mode 100644 index 0000000000000..481448d64b1aa --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/structural-match.rs @@ -0,0 +1,21 @@ +#![feature(const_fn, type_alias_impl_trait)] + +type Foo = impl Send; + +// This is not structural-match +struct A; + +const fn value() -> Foo { + A +} +const VALUE: Foo = value(); + +fn test() { + match todo!() { + VALUE => (), + //~^ opaque types cannot be used in patterns + _ => (), + } +} + +fn main() { } diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr new file mode 100644 index 0000000000000..ad9036a87d1d9 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr @@ -0,0 +1,8 @@ +error: opaque types cannot be used in patterns + --> $DIR/structural-match.rs:15:9 + | +LL | VALUE => (), + | ^^^^^ + +error: aborting due to previous error + From a8ed9aa9f016c60f5fa55326f1f6a30e2be9d83e Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Mon, 13 Apr 2020 21:41:45 +0800 Subject: [PATCH 077/695] impl From<[T; N]> for Box<[T]> Based on https://github.com/rust-lang/rust/pull/68692 --- src/liballoc/boxed.rs | 19 ++++++++++++++ .../alloc-traits-impls-length-32.rs | 4 +++ .../alloc-types-no-impls-length-33.rs | 2 ++ .../alloc-types-no-impls-length-33.stderr | 25 ++++++++++++++----- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8ef6090c743a9..8cc6f04c0653a 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -865,6 +865,25 @@ impl From> for Box<[u8]> { } } +#[stable(feature = "box_from_array", since = "1.45.0")] +impl From<[T; N]> for Box<[T]> +where + [T; N]: LengthAtMost32, +{ + /// Converts a `[T; N]` into a `Box<[T]>` + /// + /// This conversion moves the array to newly heap-allocated memory. + /// + /// # Examples + /// ```rust + /// let boxed: Box<[u8]> = Box::from([4, 2]); + /// println!("{:?}", boxed); + /// ``` + fn from(array: [T; N]) -> Box<[T]> { + box array + } +} + #[stable(feature = "boxed_slice_try_from", since = "1.43.0")] impl TryFrom> for Box<[T; N]> where diff --git a/src/test/ui/const-generics/array-impls/alloc-traits-impls-length-32.rs b/src/test/ui/const-generics/array-impls/alloc-traits-impls-length-32.rs index 0d0765e971d50..b4a083636b64f 100644 --- a/src/test/ui/const-generics/array-impls/alloc-traits-impls-length-32.rs +++ b/src/test/ui/const-generics/array-impls/alloc-traits-impls-length-32.rs @@ -18,6 +18,10 @@ pub fn yes_array_into_vec() -> Vec { [].into() } +pub fn yes_array_into_box() -> Box<[T]> { + [].into() +} + use std::collections::VecDeque; pub fn yes_vecdeque_partial_eq_array() -> impl PartialEq<[B; 32]> diff --git a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.rs b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.rs index 4b195f3a06edc..48cf21d489ada 100644 --- a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.rs +++ b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.rs @@ -12,6 +12,8 @@ pub fn no_box() { let boxed_array = >::try_from(boxed_slice); //~^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::From>` is not satisfied //~^^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom>` is not satisfied + let boxed_slice = >::from([0; 33]); + //~^ 15:42: 15:49: arrays only have std trait implementations for lengths 0..=32 [E0277] } pub fn no_rc() { diff --git a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr index ce1c9ae551ea5..5c01603ab881c 100644 --- a/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/alloc-types-no-impls-length-33.stderr @@ -18,10 +18,23 @@ LL | let boxed_array = >::try_from(boxed_slice); as std::convert::From<&str>> as std::convert::From>> as std::convert::From> - and 21 others + and 22 others = note: required because of the requirements on the impl of `std::convert::Into>` for `std::boxed::Box<[i32]>` = note: required because of the requirements on the impl of `std::convert::TryFrom>` for `std::boxed::Box<[i32; 33]>` +error[E0277]: arrays only have std trait implementations for lengths 0..=32 + --> $DIR/alloc-types-no-impls-length-33.rs:15:42 + | +LL | let boxed_slice = >::from([0; 33]); + | ^^^^^^^ + | | + | expected an implementor of trait `std::convert::From<[{integer}; 33]>` + | help: consider borrowing here: `&[0; 33]` + | + = note: the trait bound `[i32; 33]: std::convert::From<[{integer}; 33]>` is not satisfied + = note: required because of the requirements on the impl of `std::convert::From<[i32; 33]>` for `std::boxed::Box<[i32]>` + = note: required by `std::convert::From::from` + error[E0277]: the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom>` is not satisfied --> $DIR/alloc-types-no-impls-length-33.rs:12:23 | @@ -32,7 +45,7 @@ LL | let boxed_array = >::try_from(boxed_slice); as std::convert::TryFrom>> error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::From>` is not satisfied - --> $DIR/alloc-types-no-impls-length-33.rs:19:23 + --> $DIR/alloc-types-no-impls-length-33.rs:21:23 | LL | let boxed_array = >::try_from(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From>` is not implemented for `std::rc::Rc<[i32; 33]>` @@ -47,7 +60,7 @@ LL | let boxed_array = >::try_from(boxed_slice); = note: required because of the requirements on the impl of `std::convert::TryFrom>` for `std::rc::Rc<[i32; 33]>` error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::TryFrom>` is not satisfied - --> $DIR/alloc-types-no-impls-length-33.rs:19:23 + --> $DIR/alloc-types-no-impls-length-33.rs:21:23 | LL | let boxed_array = >::try_from(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom>` is not implemented for `std::rc::Rc<[i32; 33]>` @@ -56,7 +69,7 @@ LL | let boxed_array = >::try_from(boxed_slice); as std::convert::TryFrom>> error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::From>` is not satisfied - --> $DIR/alloc-types-no-impls-length-33.rs:26:23 + --> $DIR/alloc-types-no-impls-length-33.rs:28:23 | LL | let boxed_array = >::try_from(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From>` is not implemented for `std::sync::Arc<[i32; 33]>` @@ -71,7 +84,7 @@ LL | let boxed_array = >::try_from(boxed_slice); = note: required because of the requirements on the impl of `std::convert::TryFrom>` for `std::sync::Arc<[i32; 33]>` error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::TryFrom>` is not satisfied - --> $DIR/alloc-types-no-impls-length-33.rs:26:23 + --> $DIR/alloc-types-no-impls-length-33.rs:28:23 | LL | let boxed_array = >::try_from(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom>` is not implemented for `std::sync::Arc<[i32; 33]>` @@ -79,6 +92,6 @@ LL | let boxed_array = >::try_from(boxed_slice); = help: the following implementations were found: as std::convert::TryFrom>> -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0277`. From e9ae64cca7fd5f88b8c94dbb464594ca13f26792 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 May 2020 12:02:52 +0200 Subject: [PATCH 078/695] Improve E0599 explanation --- src/librustc_error_codes/error_codes/E0599.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/librustc_error_codes/error_codes/E0599.md b/src/librustc_error_codes/error_codes/E0599.md index c44e60571e1e3..5b1590b29998f 100644 --- a/src/librustc_error_codes/error_codes/E0599.md +++ b/src/librustc_error_codes/error_codes/E0599.md @@ -9,3 +9,18 @@ let x = Mouth; x.chocolate(); // error: no method named `chocolate` found for type `Mouth` // in the current scope ``` + +In this case, you need to implement the `chocolate` method to fix the error: + +``` +struct Mouth; + +impl Mouth { + fn chocolate(&self) { // We implement the `chocolate` method here. + println!("Hmmm! I love chocolate!"); + } +} + +let x = Mouth; +x.chocolate(); // ok! +``` From da9b138ec7645d483112c6b20e91ab595326c41d Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 19 May 2020 16:12:03 +0200 Subject: [PATCH 079/695] Update test after const_ptr functions are must_use now --- tests/ui/ptr_offset_with_cast.fixed | 12 ++++++------ tests/ui/ptr_offset_with_cast.rs | 12 ++++++------ tests/ui/ptr_offset_with_cast.stderr | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/ui/ptr_offset_with_cast.fixed b/tests/ui/ptr_offset_with_cast.fixed index ebdd6c4003d19..718e391e8bf69 100644 --- a/tests/ui/ptr_offset_with_cast.fixed +++ b/tests/ui/ptr_offset_with_cast.fixed @@ -9,12 +9,12 @@ fn main() { let offset_isize = 1_isize; unsafe { - ptr.add(offset_usize); - ptr.offset(offset_isize as isize); - ptr.offset(offset_u8 as isize); + let _ = ptr.add(offset_usize); + let _ = ptr.offset(offset_isize as isize); + let _ = ptr.offset(offset_u8 as isize); - ptr.wrapping_add(offset_usize); - ptr.wrapping_offset(offset_isize as isize); - ptr.wrapping_offset(offset_u8 as isize); + let _ = ptr.wrapping_add(offset_usize); + let _ = ptr.wrapping_offset(offset_isize as isize); + let _ = ptr.wrapping_offset(offset_u8 as isize); } } diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs index 3416c4b727a53..f613742c741ef 100644 --- a/tests/ui/ptr_offset_with_cast.rs +++ b/tests/ui/ptr_offset_with_cast.rs @@ -9,12 +9,12 @@ fn main() { let offset_isize = 1_isize; unsafe { - ptr.offset(offset_usize as isize); - ptr.offset(offset_isize as isize); - ptr.offset(offset_u8 as isize); + let _ = ptr.offset(offset_usize as isize); + let _ = ptr.offset(offset_isize as isize); + let _ = ptr.offset(offset_u8 as isize); - ptr.wrapping_offset(offset_usize as isize); - ptr.wrapping_offset(offset_isize as isize); - ptr.wrapping_offset(offset_u8 as isize); + let _ = ptr.wrapping_offset(offset_usize as isize); + let _ = ptr.wrapping_offset(offset_isize as isize); + let _ = ptr.wrapping_offset(offset_u8 as isize); } } diff --git a/tests/ui/ptr_offset_with_cast.stderr b/tests/ui/ptr_offset_with_cast.stderr index b5c7a03e2775e..fd45224ca067f 100644 --- a/tests/ui/ptr_offset_with_cast.stderr +++ b/tests/ui/ptr_offset_with_cast.stderr @@ -1,16 +1,16 @@ error: use of `offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:12:9 + --> $DIR/ptr_offset_with_cast.rs:12:17 | -LL | ptr.offset(offset_usize as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)` +LL | let _ = ptr.offset(offset_usize as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)` | = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings` error: use of `wrapping_offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:16:9 + --> $DIR/ptr_offset_with_cast.rs:16:17 | -LL | ptr.wrapping_offset(offset_usize as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)` +LL | let _ = ptr.wrapping_offset(offset_usize as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)` error: aborting due to 2 previous errors From f28f1f15da825bcf5cf78413f464dfea0bc553e5 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 20 May 2020 13:32:53 +0200 Subject: [PATCH 080/695] Fix dogfood fallout --- clippy_lints/src/utils/inspector.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 748c11fac64ff..9b672b9ec225b 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -289,21 +289,21 @@ fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}operands:", ind); for op in asm.operands { match op { - hir::InlineAsmOperand::In { expr, .. } => print_expr(cx, expr, indent + 1), + hir::InlineAsmOperand::In { expr, .. } + | hir::InlineAsmOperand::InOut { expr, .. } + | hir::InlineAsmOperand::Const { expr } + | hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1), hir::InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { print_expr(cx, expr, indent + 1); } }, - hir::InlineAsmOperand::InOut { expr, .. } => print_expr(cx, expr, indent + 1), hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { print_expr(cx, in_expr, indent + 1); if let Some(out_expr) = out_expr { print_expr(cx, out_expr, indent + 1); } }, - hir::InlineAsmOperand::Const { expr } => print_expr(cx, expr, indent + 1), - hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1), } } }, From 8ac1699ea15bf8d6d9bcecec4c340c88cf20c0da Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 20 May 2020 07:40:42 -0400 Subject: [PATCH 081/695] [self-profling] Record the cgu name when doing codegen for a module --- src/librustc_codegen_llvm/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index e5f73473b72a6..3e17a51528e3e 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -100,7 +100,7 @@ pub fn compile_codegen_unit( tcx: TyCtxt<'tcx>, cgu_name: Symbol, ) -> (ModuleCodegen, u64) { - let prof_timer = tcx.prof.generic_activity("codegen_module"); + let prof_timer = tcx.prof.generic_activity_with_arg("codegen_module", cgu_name.to_string()); let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); From cad8fe90fd61c410ac3e7e97a6be37c96ca66a72 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 21:09:57 +0200 Subject: [PATCH 082/695] rename `Predicate` to `PredicateKind`, introduce alias --- .../infer/canonical/query_response.rs | 10 +- src/librustc_infer/infer/combine.rs | 2 +- src/librustc_infer/infer/outlives/mod.rs | 20 ++-- src/librustc_infer/infer/sub.rs | 2 +- src/librustc_infer/traits/util.rs | 60 ++++++------ src/librustc_lint/builtin.rs | 6 +- src/librustc_lint/unused.rs | 2 +- src/librustc_middle/ty/codec.rs | 4 +- src/librustc_middle/ty/mod.rs | 98 ++++++++++--------- src/librustc_middle/ty/print/pretty.rs | 18 ++-- src/librustc_middle/ty/structural_impls.rs | 56 ++++++----- src/librustc_middle/ty/sty.rs | 2 +- .../borrow_check/diagnostics/region_errors.rs | 2 +- .../borrow_check/type_check/mod.rs | 10 +- .../transform/qualify_min_const_fn.rs | 24 ++--- src/librustc_privacy/lib.rs | 8 +- src/librustc_trait_selection/opaque_types.rs | 22 ++--- .../traits/auto_trait.rs | 16 +-- .../traits/error_reporting/mod.rs | 36 +++---- .../traits/error_reporting/suggestions.rs | 2 +- .../traits/fulfill.rs | 18 ++-- src/librustc_trait_selection/traits/mod.rs | 2 +- .../traits/object_safety.rs | 40 ++++---- .../traits/project.rs | 8 +- .../traits/query/type_op/prove_predicate.rs | 4 +- src/librustc_trait_selection/traits/select.rs | 22 ++--- src/librustc_trait_selection/traits/wf.rs | 38 +++---- .../implied_outlives_bounds.rs | 20 ++-- .../normalize_erasing_regions.rs | 18 ++-- src/librustc_traits/type_op.rs | 7 +- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/closure.rs | 6 +- src/librustc_typeck/check/coercion.rs | 4 +- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/dropck.rs | 6 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 20 ++-- src/librustc_typeck/check/method/suggest.rs | 10 +- src/librustc_typeck/check/mod.rs | 38 +++---- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/collect.rs | 14 +-- .../constrained_generic_params.rs | 2 +- .../impl_wf_check/min_specialization.rs | 26 ++--- src/librustc_typeck/outlives/explicit.rs | 20 ++-- src/librustc_typeck/outlives/mod.rs | 8 +- src/librustdoc/clean/auto_trait.rs | 6 +- src/librustdoc/clean/mod.rs | 28 +++--- src/librustdoc/clean/simplify.rs | 2 +- .../clippy_lints/src/future_not_send.rs | 2 +- .../clippy/clippy_lints/src/methods/mod.rs | 4 +- .../src/needless_pass_by_value.rs | 2 +- .../clippy/clippy_lints/src/utils/mod.rs | 2 +- 53 files changed, 406 insertions(+), 383 deletions(-) diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index c7a7cf89b4f1b..67c8265cb1153 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -532,12 +532,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { cause.clone(), param_env, match k1.unpack() { - GenericArgKind::Lifetime(r1) => ty::Predicate::RegionOutlives( + GenericArgKind::Lifetime(r1) => ty::PredicateKind::RegionOutlives( ty::Binder::bind(ty::OutlivesPredicate(r1, r2)), ), - GenericArgKind::Type(t1) => { - ty::Predicate::TypeOutlives(ty::Binder::bind(ty::OutlivesPredicate(t1, r2))) - } + GenericArgKind::Type(t1) => ty::PredicateKind::TypeOutlives(ty::Binder::bind( + ty::OutlivesPredicate(t1, r2), + )), GenericArgKind::Const(..) => { // Consts cannot outlive one another, so we don't expect to // ecounter this branch. @@ -664,7 +664,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { self.obligations.push(Obligation { cause: self.cause.clone(), param_env: self.param_env, - predicate: ty::Predicate::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate( + predicate: ty::PredicateKind::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate( sup, sub, ))), recursion_depth: 0, diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 3467457b44997..2a188b2120556 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -307,7 +307,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - ty::Predicate::WellFormed(b_ty), + ty::PredicateKind::WellFormed(b_ty), )); } diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index 289457e2bd0c2..e423137da8f74 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -12,16 +12,16 @@ pub fn explicit_outlives_bounds<'tcx>( ) -> impl Iterator> + 'tcx { debug!("explicit_outlives_bounds()"); param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate { - ty::Predicate::Projection(..) - | ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => None, - ty::Predicate::RegionOutlives(ref data) => data + ty::PredicateKind::Projection(..) + | ty::PredicateKind::Trait(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::TypeOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => None, + ty::PredicateKind::RegionOutlives(ref data) => data .no_bound_vars() .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), }) diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 1ec67ef2efa9d..22231488b7b5c 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -100,7 +100,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { self.fields.obligations.push(Obligation::new( self.fields.trace.cause.clone(), self.fields.param_env, - ty::Predicate::Subtype(ty::Binder::dummy(ty::SubtypePredicate { + ty::PredicateKind::Subtype(ty::Binder::dummy(ty::SubtypePredicate { a_is_expected: self.a_is_expected, a, b, diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index ee903b676bae9..400fe4d1321ca 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -11,39 +11,39 @@ pub fn anonymize_predicate<'tcx>( pred: &ty::Predicate<'tcx>, ) -> ty::Predicate<'tcx> { match *pred { - ty::Predicate::Trait(ref data, constness) => { - ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness) + ty::PredicateKind::Trait(ref data, constness) => { + ty::PredicateKind::Trait(tcx.anonymize_late_bound_regions(data), constness) } - ty::Predicate::RegionOutlives(ref data) => { - ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data)) + ty::PredicateKind::RegionOutlives(ref data) => { + ty::PredicateKind::RegionOutlives(tcx.anonymize_late_bound_regions(data)) } - ty::Predicate::TypeOutlives(ref data) => { - ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data)) + ty::PredicateKind::TypeOutlives(ref data) => { + ty::PredicateKind::TypeOutlives(tcx.anonymize_late_bound_regions(data)) } - ty::Predicate::Projection(ref data) => { - ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data)) + ty::PredicateKind::Projection(ref data) => { + ty::PredicateKind::Projection(tcx.anonymize_late_bound_regions(data)) } - ty::Predicate::WellFormed(data) => ty::Predicate::WellFormed(data), + ty::PredicateKind::WellFormed(data) => ty::PredicateKind::WellFormed(data), - ty::Predicate::ObjectSafe(data) => ty::Predicate::ObjectSafe(data), + ty::PredicateKind::ObjectSafe(data) => ty::PredicateKind::ObjectSafe(data), - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) + ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { + ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) } - ty::Predicate::Subtype(ref data) => { - ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)) + ty::PredicateKind::Subtype(ref data) => { + ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data)) } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - ty::Predicate::ConstEvaluatable(def_id, substs) + ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(def_id, substs) } - ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2), + ty::PredicateKind::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2), } } @@ -146,7 +146,7 @@ impl Elaborator<'tcx> { fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) { let tcx = self.visited.tcx; match obligation.predicate { - ty::Predicate::Trait(ref data, _) => { + ty::PredicateKind::Trait(ref data, _) => { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); @@ -167,36 +167,36 @@ impl Elaborator<'tcx> { self.stack.extend(obligations); } - ty::Predicate::WellFormed(..) => { + ty::PredicateKind::WellFormed(..) => { // Currently, we do not elaborate WF predicates, // although we easily could. } - ty::Predicate::ObjectSafe(..) => { + ty::PredicateKind::ObjectSafe(..) => { // Currently, we do not elaborate object-safe // predicates. } - ty::Predicate::Subtype(..) => { + ty::PredicateKind::Subtype(..) => { // Currently, we do not "elaborate" predicates like `X <: Y`, // though conceivably we might. } - ty::Predicate::Projection(..) => { + ty::PredicateKind::Projection(..) => { // Nothing to elaborate in a projection predicate. } - ty::Predicate::ClosureKind(..) => { + ty::PredicateKind::ClosureKind(..) => { // Nothing to elaborate when waiting for a closure's kind to be inferred. } - ty::Predicate::ConstEvaluatable(..) => { + ty::PredicateKind::ConstEvaluatable(..) => { // Currently, we do not elaborate const-evaluatable // predicates. } - ty::Predicate::ConstEquate(..) => { + ty::PredicateKind::ConstEquate(..) => { // Currently, we do not elaborate const-equate // predicates. } - ty::Predicate::RegionOutlives(..) => { + ty::PredicateKind::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. } - ty::Predicate::TypeOutlives(ref data) => { + ty::PredicateKind::TypeOutlives(ref data) => { // We know that `T: 'a` for some type `T`. We can // often elaborate this. For example, if we know that // `[U]: 'a`, that implies that `U: 'a`. Similarly, if @@ -228,7 +228,7 @@ impl Elaborator<'tcx> { if r.is_late_bound() { None } else { - Some(ty::Predicate::RegionOutlives(ty::Binder::dummy( + Some(ty::PredicateKind::RegionOutlives(ty::Binder::dummy( ty::OutlivesPredicate(r, r_min), ))) } @@ -236,7 +236,7 @@ impl Elaborator<'tcx> { Component::Param(p) => { let ty = tcx.mk_ty_param(p.index, p.name); - Some(ty::Predicate::TypeOutlives(ty::Binder::dummy( + Some(ty::PredicateKind::TypeOutlives(ty::Binder::dummy( ty::OutlivesPredicate(ty, r_min), ))) } @@ -317,7 +317,7 @@ impl<'tcx, I: Iterator>> Iterator for FilterToT fn next(&mut self) -> Option> { while let Some(obligation) = self.base_iterator.next() { - if let ty::Predicate::Trait(data, _) = obligation.predicate { + if let ty::PredicateKind::Trait(data, _) = obligation.predicate { return Some(data.to_poly_trait_ref()); } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index bca91fb7b5d16..6e1258e25bbaf 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1202,7 +1202,7 @@ declare_lint_pass!( impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'tcx>) { use rustc_middle::ty::fold::TypeFoldable; - use rustc_middle::ty::Predicate::*; + use rustc_middle::ty::PredicateKind::*; if cx.tcx.features().trivial_bounds { let def_id = cx.tcx.hir().local_def_id(item.hir_id); @@ -1498,7 +1498,7 @@ impl ExplicitOutlivesRequirements { inferred_outlives .iter() .filter_map(|(pred, _)| match pred { - ty::Predicate::RegionOutlives(outlives) => { + ty::PredicateKind::RegionOutlives(outlives) => { let outlives = outlives.skip_binder(); match outlives.0 { ty::ReEarlyBound(ebr) if ebr.index == index => Some(outlives.1), @@ -1517,7 +1517,7 @@ impl ExplicitOutlivesRequirements { inferred_outlives .iter() .filter_map(|(pred, _)| match pred { - ty::Predicate::TypeOutlives(outlives) => { + ty::PredicateKind::TypeOutlives(outlives) => { let outlives = outlives.skip_binder(); outlives.0.is_param(index).then_some(outlives.1) } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index c24079a6e4be2..19146f68fce80 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty::Opaque(def, _) => { let mut has_emitted = false; for (predicate, _) in cx.tcx.predicates_of(def).predicates { - if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate { + if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; let descr_pre = diff --git a/src/librustc_middle/ty/codec.rs b/src/librustc_middle/ty/codec.rs index cbbc937ed7d31..7ebeb6243be41 100644 --- a/src/librustc_middle/ty/codec.rs +++ b/src/librustc_middle/ty/codec.rs @@ -201,9 +201,9 @@ where assert!(pos >= SHORTHAND_OFFSET); let shorthand = pos - SHORTHAND_OFFSET; - decoder.with_position(shorthand, ty::Predicate::decode) + decoder.with_position(shorthand, ty::PredicateKind::decode) } else { - ty::Predicate::decode(decoder) + ty::PredicateKind::decode(decoder) }?; Ok((predicate, Decodable::decode(decoder)?)) }) diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 36bc44f5e5032..e3aeb242dc034 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1016,9 +1016,11 @@ impl<'tcx> GenericPredicates<'tcx> { } } +pub type Predicate<'tcx> = PredicateKind<'tcx>; + #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] #[derive(HashStable, TypeFoldable)] -pub enum Predicate<'tcx> { +pub enum PredicateKind<'tcx> { /// Corresponds to `where Foo: Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. @@ -1079,7 +1081,7 @@ impl<'tcx> AsRef> for Predicate<'tcx> { } } -impl<'tcx> Predicate<'tcx> { +impl<'tcx> PredicateKind<'tcx> { /// Performs a substitution suitable for going from a /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal @@ -1152,31 +1154,31 @@ impl<'tcx> Predicate<'tcx> { let substs = &trait_ref.skip_binder().substs; match *self { - Predicate::Trait(ref binder, constness) => { - Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) + PredicateKind::Trait(ref binder, constness) => { + PredicateKind::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) } - Predicate::Subtype(ref binder) => { - Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs))) + PredicateKind::Subtype(ref binder) => { + PredicateKind::Subtype(binder.map_bound(|data| data.subst(tcx, substs))) } - Predicate::RegionOutlives(ref binder) => { - Predicate::RegionOutlives(binder.map_bound(|data| data.subst(tcx, substs))) + PredicateKind::RegionOutlives(ref binder) => { + PredicateKind::RegionOutlives(binder.map_bound(|data| data.subst(tcx, substs))) } - Predicate::TypeOutlives(ref binder) => { - Predicate::TypeOutlives(binder.map_bound(|data| data.subst(tcx, substs))) + PredicateKind::TypeOutlives(ref binder) => { + PredicateKind::TypeOutlives(binder.map_bound(|data| data.subst(tcx, substs))) } - Predicate::Projection(ref binder) => { - Predicate::Projection(binder.map_bound(|data| data.subst(tcx, substs))) + PredicateKind::Projection(ref binder) => { + PredicateKind::Projection(binder.map_bound(|data| data.subst(tcx, substs))) } - Predicate::WellFormed(data) => Predicate::WellFormed(data.subst(tcx, substs)), - Predicate::ObjectSafe(trait_def_id) => Predicate::ObjectSafe(trait_def_id), - Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - Predicate::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind) + PredicateKind::WellFormed(data) => PredicateKind::WellFormed(data.subst(tcx, substs)), + PredicateKind::ObjectSafe(trait_def_id) => PredicateKind::ObjectSafe(trait_def_id), + PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { + PredicateKind::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind) } - Predicate::ConstEvaluatable(def_id, const_substs) => { - Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)) + PredicateKind::ConstEvaluatable(def_id, const_substs) => { + PredicateKind::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)) } - Predicate::ConstEquate(c1, c2) => { - Predicate::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) + PredicateKind::ConstEquate(c1, c2) => { + PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) } } } @@ -1298,7 +1300,7 @@ pub trait ToPredicate<'tcx> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait( + ty::PredicateKind::Trait( ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value }), self.constness, ) @@ -1307,7 +1309,7 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait( + ty::PredicateKind::Trait( ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }), self.constness, ) @@ -1316,62 +1318,62 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) + ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness) } } impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) + ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness) } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::RegionOutlives(*self) + PredicateKind::RegionOutlives(*self) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::TypeOutlives(*self) + PredicateKind::TypeOutlives(*self) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::Projection(*self) + PredicateKind::Projection(*self) } } -impl<'tcx> Predicate<'tcx> { +impl<'tcx> PredicateKind<'tcx> { pub fn to_opt_poly_trait_ref(&self) -> Option> { match *self { - Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()), - Predicate::Projection(..) - | Predicate::Subtype(..) - | Predicate::RegionOutlives(..) - | Predicate::WellFormed(..) - | Predicate::ObjectSafe(..) - | Predicate::ClosureKind(..) - | Predicate::TypeOutlives(..) - | Predicate::ConstEvaluatable(..) - | Predicate::ConstEquate(..) => None, + PredicateKind::Trait(ref t, _) => Some(t.to_poly_trait_ref()), + PredicateKind::Projection(..) + | PredicateKind::Subtype(..) + | PredicateKind::RegionOutlives(..) + | PredicateKind::WellFormed(..) + | PredicateKind::ObjectSafe(..) + | PredicateKind::ClosureKind(..) + | PredicateKind::TypeOutlives(..) + | PredicateKind::ConstEvaluatable(..) + | PredicateKind::ConstEquate(..) => None, } } pub fn to_opt_type_outlives(&self) -> Option> { match *self { - Predicate::TypeOutlives(data) => Some(data), - Predicate::Trait(..) - | Predicate::Projection(..) - | Predicate::Subtype(..) - | Predicate::RegionOutlives(..) - | Predicate::WellFormed(..) - | Predicate::ObjectSafe(..) - | Predicate::ClosureKind(..) - | Predicate::ConstEvaluatable(..) - | Predicate::ConstEquate(..) => None, + PredicateKind::TypeOutlives(data) => Some(data), + PredicateKind::Trait(..) + | PredicateKind::Projection(..) + | PredicateKind::Subtype(..) + | PredicateKind::RegionOutlives(..) + | PredicateKind::WellFormed(..) + | PredicateKind::ObjectSafe(..) + | PredicateKind::ClosureKind(..) + | PredicateKind::ConstEvaluatable(..) + | PredicateKind::ConstEquate(..) => None, } } } diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 2502a4a13a8f0..c224c937b07fe 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2032,28 +2032,28 @@ define_print_and_forward_display! { ty::Predicate<'tcx> { match *self { - ty::Predicate::Trait(ref data, constness) => { + ty::PredicateKind::Trait(ref data, constness) => { if let hir::Constness::Const = constness { p!(write("const ")); } p!(print(data)) } - ty::Predicate::Subtype(ref predicate) => p!(print(predicate)), - ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)), - ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)), - ty::Predicate::Projection(ref predicate) => p!(print(predicate)), - ty::Predicate::WellFormed(ty) => p!(print(ty), write(" well-formed")), - ty::Predicate::ObjectSafe(trait_def_id) => { + ty::PredicateKind::Subtype(ref predicate) => p!(print(predicate)), + ty::PredicateKind::RegionOutlives(ref predicate) => p!(print(predicate)), + ty::PredicateKind::TypeOutlives(ref predicate) => p!(print(predicate)), + ty::PredicateKind::Projection(ref predicate) => p!(print(predicate)), + ty::PredicateKind::WellFormed(ty) => p!(print(ty), write(" well-formed")), + ty::PredicateKind::ObjectSafe(trait_def_id) => { p!(write("the trait `"), print_def_path(trait_def_id, &[]), write("` is object-safe")) } - ty::Predicate::ClosureKind(closure_def_id, _closure_substs, kind) => { + ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => { p!(write("the closure `"), print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind)) } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(def_id, substs) => { p!(write("the constant `"), print_value_path(def_id, substs), write("` can be evaluated")) diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index c23a351ac515c..54f34a3e07815 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -219,25 +219,27 @@ impl fmt::Debug for ty::ProjectionPredicate<'tcx> { } } -impl fmt::Debug for ty::Predicate<'tcx> { +impl fmt::Debug for ty::PredicateKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::Predicate::Trait(ref a, constness) => { + ty::PredicateKind::Trait(ref a, constness) => { if let hir::Constness::Const = constness { write!(f, "const ")?; } a.fmt(f) } - ty::Predicate::Subtype(ref pair) => pair.fmt(f), - ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f), - ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f), - ty::Predicate::Projection(ref pair) => pair.fmt(f), - ty::Predicate::WellFormed(ty) => write!(f, "WellFormed({:?})", ty), - ty::Predicate::ObjectSafe(trait_def_id) => write!(f, "ObjectSafe({:?})", trait_def_id), - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + ty::PredicateKind::Subtype(ref pair) => pair.fmt(f), + ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f), + ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f), + ty::PredicateKind::Projection(ref pair) => pair.fmt(f), + ty::PredicateKind::WellFormed(ty) => write!(f, "WellFormed({:?})", ty), + ty::PredicateKind::ObjectSafe(trait_def_id) => { + write!(f, "ObjectSafe({:?})", trait_def_id) + } + ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(def_id, substs) => { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), @@ -471,30 +473,32 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { type Lifted = ty::Predicate<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { match *self { - ty::Predicate::Trait(ref binder, constness) => { - tcx.lift(binder).map(|binder| ty::Predicate::Trait(binder, constness)) + ty::PredicateKind::Trait(ref binder, constness) => { + tcx.lift(binder).map(|binder| ty::PredicateKind::Trait(binder, constness)) + } + ty::PredicateKind::Subtype(ref binder) => { + tcx.lift(binder).map(ty::PredicateKind::Subtype) } - ty::Predicate::Subtype(ref binder) => tcx.lift(binder).map(ty::Predicate::Subtype), - ty::Predicate::RegionOutlives(ref binder) => { - tcx.lift(binder).map(ty::Predicate::RegionOutlives) + ty::PredicateKind::RegionOutlives(ref binder) => { + tcx.lift(binder).map(ty::PredicateKind::RegionOutlives) } - ty::Predicate::TypeOutlives(ref binder) => { - tcx.lift(binder).map(ty::Predicate::TypeOutlives) + ty::PredicateKind::TypeOutlives(ref binder) => { + tcx.lift(binder).map(ty::PredicateKind::TypeOutlives) } - ty::Predicate::Projection(ref binder) => { - tcx.lift(binder).map(ty::Predicate::Projection) + ty::PredicateKind::Projection(ref binder) => { + tcx.lift(binder).map(ty::PredicateKind::Projection) } - ty::Predicate::WellFormed(ty) => tcx.lift(&ty).map(ty::Predicate::WellFormed), - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + ty::PredicateKind::WellFormed(ty) => tcx.lift(&ty).map(ty::PredicateKind::WellFormed), + ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { tcx.lift(&closure_substs).map(|closure_substs| { - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) + ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) }) } - ty::Predicate::ObjectSafe(trait_def_id) => { - Some(ty::Predicate::ObjectSafe(trait_def_id)) + ty::PredicateKind::ObjectSafe(trait_def_id) => { + Some(ty::PredicateKind::ObjectSafe(trait_def_id)) } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - tcx.lift(&substs).map(|substs| ty::Predicate::ConstEvaluatable(def_id, substs)) + ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + tcx.lift(&substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs)) } ty::Predicate::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::Predicate::ConstEquate(c1, c2)) diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 2ad673b2c1943..8962b243911b2 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -615,7 +615,7 @@ impl<'tcx> Binder> { Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate() } ExistentialPredicate::Projection(p) => { - ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty))) + ty::PredicateKind::Projection(Binder(p.with_self_ty(tcx, self_ty))) } ExistentialPredicate::AutoTrait(did) => { let trait_ref = diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 98c0542f9c0dc..d7ea88725ed1b 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -576,7 +576,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut found = false; for predicate in bounds.predicates { - if let ty::Predicate::TypeOutlives(binder) = predicate { + if let ty::PredicateKind::TypeOutlives(binder) = predicate { if let ty::OutlivesPredicate(_, ty::RegionKind::ReStatic) = binder.skip_binder() { diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 08aa434010710..d3b1b92bdcd10 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1016,7 +1016,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.prove_predicate( - ty::Predicate::WellFormed(inferred_ty), + ty::PredicateKind::WellFormed(inferred_ty), Locations::All(span), ConstraintCategory::TypeAnnotation, ); @@ -1268,7 +1268,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { obligations.obligations.push(traits::Obligation::new( ObligationCause::dummy(), param_env, - ty::Predicate::WellFormed(revealed_ty), + ty::PredicateKind::WellFormed(revealed_ty), )); obligations.add( infcx @@ -1612,7 +1612,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_call_dest(body, term, &sig, destination, term_location); self.prove_predicates( - sig.inputs_and_output.iter().map(|ty| ty::Predicate::WellFormed(ty)), + sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty)), term_location.to_locations(), ConstraintCategory::Boring, ); @@ -2017,7 +2017,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { traits::ObligationCauseCode::RepeatVec(should_suggest), ), self.param_env, - ty::Predicate::Trait( + ty::PredicateKind::Trait( ty::Binder::bind(ty::TraitPredicate { trait_ref: ty::TraitRef::new( self.tcx().require_lang_item( @@ -2686,7 +2686,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory, ) { self.prove_predicates( - Some(ty::Predicate::Trait( + Some(ty::PredicateKind::Trait( trait_ref.to_poly_trait_ref().to_poly_trait_predicate(), hir::Constness::NotConst, )), diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 0750284889391..7fdf9133dd4b9 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::*; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, adjustment::PointerCast, Predicate, Ty, TyCtxt}; +use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::borrow::Cow; @@ -24,20 +24,22 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - let predicates = tcx.predicates_of(current); for (predicate, _) in predicates.predicates { match predicate { - Predicate::RegionOutlives(_) - | Predicate::TypeOutlives(_) - | Predicate::WellFormed(_) - | Predicate::Projection(_) - | Predicate::ConstEvaluatable(..) - | Predicate::ConstEquate(..) => continue, - Predicate::ObjectSafe(_) => { + ty::PredicateKind::RegionOutlives(_) + | ty::PredicateKind::TypeOutlives(_) + | ty::PredicateKind::WellFormed(_) + | ty::PredicateKind::Projection(_) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => continue, + ty::PredicateKind::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } - Predicate::ClosureKind(..) => { + ty::PredicateKind::ClosureKind(..) => { bug!("closure kind predicate on function: {:#?}", predicate) } - Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate), - Predicate::Trait(pred, constness) => { + ty::PredicateKind::Subtype(_) => { + bug!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateKind::Trait(pred, constness) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index b474b23ac4f5c..64a2a9055f323 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -91,13 +91,13 @@ where let ty::GenericPredicates { parent: _, predicates } = predicates; for (predicate, _span) in predicates { match predicate { - ty::Predicate::Trait(poly_predicate, _) => { + ty::PredicateKind::Trait(poly_predicate, _) => { let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder(); if self.visit_trait(trait_ref) { return true; } } - ty::Predicate::Projection(poly_predicate) => { + ty::PredicateKind::Projection(poly_predicate) => { let ty::ProjectionPredicate { projection_ty, ty } = *poly_predicate.skip_binder(); if ty.visit_with(self) { @@ -107,13 +107,13 @@ where return true; } } - ty::Predicate::TypeOutlives(poly_predicate) => { + ty::PredicateKind::TypeOutlives(poly_predicate) => { let ty::OutlivesPredicate(ty, _region) = *poly_predicate.skip_binder(); if ty.visit_with(self) { return true; } } - ty::Predicate::RegionOutlives(..) => {} + ty::PredicateKind::RegionOutlives(..) => {} _ => bug!("unexpected predicate: {:?}", predicate), } } diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 396965fcfb8b7..472f93201c382 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1168,7 +1168,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { debug!("instantiate_opaque_types: ty_var={:?}", ty_var); for predicate in &bounds.predicates { - if let ty::Predicate::Projection(projection) = &predicate { + if let ty::PredicateKind::Projection(projection) = &predicate { if projection.skip_binder().ty.references_error() { // No point on adding these obligations since there's a type error involved. return ty_var; @@ -1270,16 +1270,16 @@ crate fn required_region_bounds( .filter_map(|obligation| { debug!("required_region_bounds(obligation={:?})", obligation); match obligation.predicate { - ty::Predicate::Projection(..) - | ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => None, - ty::Predicate::TypeOutlives(predicate) => { + ty::PredicateKind::Projection(..) + | ty::PredicateKind::Trait(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => None, + ty::PredicateKind::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> // erased_self_ty : 'a` (we interpret a diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index e19ddcd9e5e98..af9623c49981d 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -341,7 +341,7 @@ impl AutoTraitFinder<'tcx> { already_visited.remove(&pred); self.add_user_pred( &mut user_computed_preds, - ty::Predicate::Trait(pred, hir::Constness::NotConst), + ty::PredicateKind::Trait(pred, hir::Constness::NotConst), ); predicates.push_back(pred); } else { @@ -411,8 +411,10 @@ impl AutoTraitFinder<'tcx> { ) { let mut should_add_new = true; user_computed_preds.retain(|&old_pred| { - if let (&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) = - (&new_pred, old_pred) + if let ( + &ty::PredicateKind::Trait(new_trait, _), + ty::PredicateKind::Trait(old_trait, _), + ) = (&new_pred, old_pred) { if new_trait.def_id() == old_trait.def_id() { let new_substs = new_trait.skip_binder().trait_ref.substs; @@ -631,7 +633,7 @@ impl AutoTraitFinder<'tcx> { // We check this by calling is_of_param on the relevant types // from the various possible predicates match &predicate { - &ty::Predicate::Trait(p, _) => { + &ty::PredicateKind::Trait(p, _) => { if self.is_param_no_infer(p.skip_binder().trait_ref.substs) && !only_projections && is_new_pred @@ -640,7 +642,7 @@ impl AutoTraitFinder<'tcx> { } predicates.push_back(p); } - &ty::Predicate::Projection(p) => { + &ty::PredicateKind::Projection(p) => { debug!( "evaluate_nested_obligations: examining projection predicate {:?}", predicate @@ -765,12 +767,12 @@ impl AutoTraitFinder<'tcx> { } } } - &ty::Predicate::RegionOutlives(ref binder) => { + &ty::PredicateKind::RegionOutlives(ref binder) => { if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { return false; } } - &ty::Predicate::TypeOutlives(ref binder) => { + &ty::PredicateKind::TypeOutlives(ref binder) => { match ( binder.no_bound_vars(), binder.map_bound_ref(|pred| pred.0).no_bound_vars(), diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 139b860072224..ac119a0c3d811 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -253,7 +253,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate, _) => { + ty::PredicateKind::Trait(ref trait_predicate, _) => { let trait_predicate = self.resolve_vars_if_possible(trait_predicate); if self.tcx.sess.has_errors() && trait_predicate.references_error() { @@ -468,7 +468,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_pred }); let unit_obligation = Obligation { - predicate: ty::Predicate::Trait( + predicate: ty::PredicateKind::Trait( predicate, hir::Constness::NotConst, ), @@ -489,14 +489,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err } - ty::Predicate::Subtype(ref predicate) => { + ty::PredicateKind::Subtype(ref predicate) => { // Errors for Subtype predicates show up as // `FulfillmentErrorCode::CodeSubtypeError`, // not selection error. span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) } - ty::Predicate::RegionOutlives(ref predicate) => { + ty::PredicateKind::RegionOutlives(ref predicate) => { let predicate = self.resolve_vars_if_possible(predicate); let err = self .region_outlives_predicate(&obligation.cause, &predicate) @@ -512,7 +512,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) } - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { + ty::PredicateKind::Projection(..) | ty::PredicateKind::TypeOutlives(..) => { let predicate = self.resolve_vars_if_possible(&obligation.predicate); struct_span_err!( self.tcx.sess, @@ -523,12 +523,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) } - ty::Predicate::ObjectSafe(trait_def_id) => { + ty::PredicateKind::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); report_object_safety_error(self.tcx, span, trait_def_id, violations) } - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { let found_kind = self.closure_kind(closure_substs).unwrap(); let closure_span = self.tcx.sess.source_map().guess_head_span( @@ -587,7 +587,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - ty::Predicate::WellFormed(ty) => { + ty::PredicateKind::WellFormed(ty) => { if !self.tcx.sess.opts.debugging_opts.chalk { // WF predicates cannot themselves make // errors. They can only block due to @@ -605,7 +605,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - ty::Predicate::ConstEvaluatable(..) => { + ty::PredicateKind::ConstEvaluatable(..) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, // not `Unimplemented`. @@ -1047,7 +1047,9 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } let (cond, error) = match (cond, error) { - (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error), + (&ty::PredicateKind::Trait(..), &ty::PredicateKind::Trait(ref error, _)) => { + (cond, error) + } _ => { // FIXME: make this work in other cases too. return false; @@ -1055,7 +1057,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { }; for obligation in super::elaborate_predicates(self.tcx, std::iter::once(*cond)) { - if let ty::Predicate::Trait(implication, _) = obligation.predicate { + if let ty::PredicateKind::Trait(implication, _) = obligation.predicate { let error = error.to_poly_trait_ref(); let implication = implication.to_poly_trait_ref(); // FIXME: I'm just not taking associated types at all here. @@ -1135,7 +1137,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // // this can fail if the problem was higher-ranked, in which // cause I have no idea for a good error message. - if let ty::Predicate::Projection(ref data) = predicate { + if let ty::PredicateKind::Projection(ref data) = predicate { let mut selcx = SelectionContext::new(self); let (data, _) = self.replace_bound_vars_with_fresh_vars( obligation.cause.span, @@ -1416,7 +1418,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } let mut err = match predicate { - ty::Predicate::Trait(ref data, _) => { + ty::PredicateKind::Trait(ref data, _) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); @@ -1515,7 +1517,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { err } - ty::Predicate::WellFormed(ty) => { + ty::PredicateKind::WellFormed(ty) => { // Same hacky approach as above to avoid deluging user // with error messages. if ty.references_error() || self.tcx.sess.has_errors() { @@ -1524,7 +1526,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) } - ty::Predicate::Subtype(ref data) => { + ty::PredicateKind::Subtype(ref data) => { if data.references_error() || self.tcx.sess.has_errors() { // no need to overload user in such cases return; @@ -1534,7 +1536,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { assert!(a.is_ty_var() && b.is_ty_var()); self.need_type_info_err(body_id, span, a, ErrorCode::E0282) } - ty::Predicate::Projection(ref data) => { + ty::PredicateKind::Projection(ref data) => { let trait_ref = data.to_poly_trait_ref(self.tcx); let self_ty = trait_ref.self_ty(); let ty = data.skip_binder().ty; @@ -1658,7 +1660,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, ) { if let ( - ty::Predicate::Trait(pred, _), + ty::PredicateKind::Trait(pred, _), ObligationCauseCode::BindingObligation(item_def_id, span), ) = (&obligation.predicate, &obligation.cause.code) { diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index b8771d59dd4bd..5baaf838caa72 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1238,7 +1238,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // bound was introduced. At least one generator should be present for this diagnostic to be // modified. let (mut trait_ref, mut target_ty) = match obligation.predicate { - ty::Predicate::Trait(p, _) => { + ty::PredicateKind::Trait(p, _) => { (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())) } _ => (None, None), diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 98f6ac0e54728..0497dec4029d1 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -323,7 +323,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { let infcx = self.selcx.infcx(); match obligation.predicate { - ty::Predicate::Trait(ref data, _) => { + ty::PredicateKind::Trait(ref data, _) => { let trait_obligation = obligation.with(*data); if data.is_global() { @@ -378,14 +378,14 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::Predicate::RegionOutlives(ref binder) => { + ty::PredicateKind::RegionOutlives(ref binder) => { match infcx.region_outlives_predicate(&obligation.cause, binder) { Ok(()) => ProcessResult::Changed(vec![]), Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), } } - ty::Predicate::TypeOutlives(ref binder) => { + ty::PredicateKind::TypeOutlives(ref binder) => { // Check if there are higher-ranked vars. match binder.no_bound_vars() { // If there are, inspect the underlying type further. @@ -429,7 +429,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::Predicate::Projection(ref data) => { + ty::PredicateKind::Projection(ref data) => { let project_obligation = obligation.with(*data); match project::poly_project_and_unify_type(self.selcx, &project_obligation) { Ok(None) => { @@ -443,7 +443,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::Predicate::ObjectSafe(trait_def_id) => { + ty::PredicateKind::ObjectSafe(trait_def_id) => { if !self.selcx.tcx().is_object_safe(trait_def_id) { ProcessResult::Error(CodeSelectionError(Unimplemented)) } else { @@ -451,7 +451,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::Predicate::ClosureKind(_, closure_substs, kind) => { + ty::PredicateKind::ClosureKind(_, closure_substs, kind) => { match self.selcx.infcx().closure_kind(closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { @@ -464,7 +464,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::Predicate::WellFormed(ty) => { + ty::PredicateKind::WellFormed(ty) => { match wf::obligations( self.selcx.infcx(), obligation.param_env, @@ -481,7 +481,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::Predicate::Subtype(ref subtype) => { + ty::PredicateKind::Subtype(ref subtype) => { match self.selcx.infcx().subtype_predicate( &obligation.cause, obligation.param_env, @@ -510,7 +510,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(def_id, substs) => { match self.selcx.infcx().const_eval_resolve( obligation.param_env, def_id, diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 9592f93ce2e76..99d434c5c9292 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -334,7 +334,7 @@ pub fn normalize_param_env_or_error<'tcx>( // TypeOutlives predicates - these are normally used by regionck. let outlives_predicates: Vec<_> = predicates .drain_filter(|predicate| match predicate { - ty::Predicate::TypeOutlives(..) => true, + ty::PredicateKind::TypeOutlives(..) => true, _ => false, }) .collect(); diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 1bfcacd6ccdc1..bb727055d03fb 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -246,7 +246,7 @@ fn predicates_reference_self( .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) .filter_map(|(predicate, &sp)| { match predicate { - ty::Predicate::Trait(ref data, _) => { + ty::PredicateKind::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. if data.skip_binder().trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) @@ -254,7 +254,7 @@ fn predicates_reference_self( None } } - ty::Predicate::Projection(ref data) => { + ty::PredicateKind::Projection(ref data) => { // And similarly for projections. This should be redundant with // the previous check because any projection should have a // matching `Trait` predicate with the same inputs, but we do @@ -276,14 +276,14 @@ fn predicates_reference_self( None } } - ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => None, + ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::TypeOutlives(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => None, } }) .collect() @@ -305,18 +305,18 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| match obligation.predicate { - ty::Predicate::Trait(ref trait_pred, _) => { + ty::PredicateKind::Trait(ref trait_pred, _) => { trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0) } - ty::Predicate::Projection(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => false, + ty::PredicateKind::Projection(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::TypeOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => false, }) } diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index c4cb72fa08c08..54b064359dcbd 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -671,7 +671,9 @@ fn prune_cache_value_obligations<'a, 'tcx>( // indirect obligations (e.g., we project to `?0`, // but we have `T: Foo` and `?1: Bar`). - ty::Predicate::Projection(ref data) => infcx.unresolved_type_vars(&data.ty()).is_some(), + ty::PredicateKind::Projection(ref data) => { + infcx.unresolved_type_vars(&data.ty()).is_some() + } // We are only interested in `T: Foo` predicates, whre // `U` references one of `unresolved_type_vars`. =) @@ -928,7 +930,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( let infcx = selcx.infcx(); for predicate in env_predicates { debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); - if let ty::Predicate::Projection(data) = predicate { + if let ty::PredicateKind::Projection(data) = predicate { let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; let is_match = same_def_id @@ -1164,7 +1166,7 @@ fn confirm_object_candidate<'cx, 'tcx>( // select only those projections that are actually projecting an // item with the correct name let env_predicates = env_predicates.filter_map(|o| match o.predicate { - ty::Predicate::Projection(data) => { + ty::PredicateKind::Projection(data) => { if data.projection_def_id() == obligation.predicate.item_def_id { Some(data) } else { diff --git a/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs index 981745af80544..c0470084072a9 100644 --- a/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs +++ b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs @@ -1,6 +1,6 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; -use rustc_middle::ty::{ParamEnvAnd, Predicate, TyCtxt}; +use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt}; pub use rustc_middle::traits::query::type_op::ProvePredicate; @@ -15,7 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // `&T`, accounts for about 60% percentage of the predicates // we have to prove. No need to canonicalize and all that for // such cases. - if let Predicate::Trait(trait_ref, _) = key.value.predicate { + if let ty::PredicateKind::Trait(trait_ref, _) = key.value.predicate { if let Some(sized_def_id) = tcx.lang_items().sized_trait() { if trait_ref.def_id() == sized_def_id { if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) { diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 70c6cbef102c5..02da6033a0064 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -414,13 +414,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.predicate { - ty::Predicate::Trait(ref t, _) => { + ty::PredicateKind::Trait(ref t, _) => { debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(*t); self.evaluate_trait_predicate_recursively(previous_stack, obligation) } - ty::Predicate::Subtype(ref p) => { + ty::PredicateKind::Subtype(ref p) => { // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { mut obligations, .. })) => { @@ -435,7 +435,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::Predicate::WellFormed(ty) => match wf::obligations( + ty::PredicateKind::WellFormed(ty) => match wf::obligations( self.infcx, obligation.param_env, obligation.cause.body_id, @@ -449,12 +449,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => Ok(EvaluatedToAmbig), }, - ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { + ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::RegionOutlives(..) => { // We do not consider region relationships when evaluating trait matches. Ok(EvaluatedToOkModuloRegions) } - ty::Predicate::ObjectSafe(trait_def_id) => { + ty::PredicateKind::ObjectSafe(trait_def_id) => { if self.tcx().is_object_safe(trait_def_id) { Ok(EvaluatedToOk) } else { @@ -462,7 +462,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::Predicate::Projection(ref data) => { + ty::PredicateKind::Projection(ref data) => { let project_obligation = obligation.with(*data); match project::poly_project_and_unify_type(self, &project_obligation) { Ok(Some(mut subobligations)) => { @@ -483,7 +483,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::Predicate::ClosureKind(_, closure_substs, kind) => { + ty::PredicateKind::ClosureKind(_, closure_substs, kind) => { match self.infcx.closure_kind(closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { @@ -496,7 +496,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(def_id, substs) => { match self.tcx().const_eval_resolve( obligation.param_env, def_id, @@ -676,7 +676,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // if the regions match exactly. let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); let cycle = cycle.map(|stack| { - ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst) + ty::PredicateKind::Trait(stack.obligation.predicate, hir::Constness::NotConst) }); if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); @@ -792,7 +792,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { let result = match predicate { - ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), + ty::PredicateKind::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), _ => false, }; debug!("coinductive_predicate({:?}) = {:?}", predicate, result); @@ -2921,7 +2921,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.push(Obligation::new( obligation.cause.clone(), obligation.param_env, - ty::Predicate::ClosureKind(closure_def_id, substs, kind), + ty::PredicateKind::ClosureKind(closure_def_id, substs, kind), )); } diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 4d3bbfa77c37d..b1b50eb2331e2 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -73,28 +73,28 @@ pub fn predicate_obligations<'a, 'tcx>( // (*) ok to skip binders, because wf code is prepared for it match *predicate { - ty::Predicate::Trait(ref t, _) => { + ty::PredicateKind::Trait(ref t, _) => { wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) } - ty::Predicate::RegionOutlives(..) => {} - ty::Predicate::TypeOutlives(ref t) => { + ty::PredicateKind::RegionOutlives(..) => {} + ty::PredicateKind::TypeOutlives(ref t) => { wf.compute(t.skip_binder().0); } - ty::Predicate::Projection(ref t) => { + ty::PredicateKind::Projection(ref t) => { let t = t.skip_binder(); // (*) wf.compute_projection(t.projection_ty); wf.compute(t.ty); } - ty::Predicate::WellFormed(t) => { + ty::PredicateKind::WellFormed(t) => { wf.compute(t); } - ty::Predicate::ObjectSafe(_) => {} - ty::Predicate::ClosureKind(..) => {} - ty::Predicate::Subtype(ref data) => { + ty::PredicateKind::ObjectSafe(_) => {} + ty::PredicateKind::ClosureKind(..) => {} + ty::PredicateKind::Subtype(ref data) => { wf.compute(data.skip_binder().a); // (*) wf.compute(data.skip_binder().b); // (*) } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateKind::ConstEvaluatable(def_id, substs) => { let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); @@ -171,7 +171,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( _ => impl_item_ref.span, }; match pred { - ty::Predicate::Projection(proj) => { + ty::PredicateKind::Projection(proj) => { // The obligation comes not from the current `impl` nor the `trait` being // implemented, but rather from a "second order" obligation, like in // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`. @@ -194,7 +194,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( } } } - ty::Predicate::Trait(pred, _) => { + ty::PredicateKind::Trait(pred, _) => { // An associated item obligation born out of the `trait` failed to be met. An example // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); @@ -276,7 +276,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map( - |ty| traits::Obligation::new(cause.clone(), param_env, ty::Predicate::WellFormed(ty)), + |ty| { + traits::Obligation::new(cause.clone(), param_env, ty::PredicateKind::WellFormed(ty)) + }, )); } @@ -305,7 +307,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); - let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); + let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); } @@ -411,9 +413,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, param_env, - ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( - rty, r, - ))), + ty::PredicateKind::TypeOutlives(ty::Binder::dummy( + ty::OutlivesPredicate(rty, r), + )), )); } } @@ -502,7 +504,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { traits::Obligation::new( cause.clone(), param_env, - ty::Predicate::ObjectSafe(did), + ty::PredicateKind::ObjectSafe(did), ) })); } @@ -528,7 +530,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, param_env, - ty::Predicate::WellFormed(ty), + ty::PredicateKind::WellFormed(ty), )); } else { // Yes, resolved, proceed with the result. diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index eaaab87ab7474..aed5729b34a2c 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -95,27 +95,27 @@ fn compute_implied_outlives_bounds<'tcx>( implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { assert!(!obligation.has_escaping_bound_vars()); match obligation.predicate { - ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::Projection(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => vec![], + ty::PredicateKind::Trait(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Projection(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => vec![], - ty::Predicate::WellFormed(subty) => { + ty::PredicateKind::WellFormed(subty) => { wf_types.push(subty); vec![] } - ty::Predicate::RegionOutlives(ref data) => match data.no_bound_vars() { + ty::PredicateKind::RegionOutlives(ref data) => match data.no_bound_vars() { None => vec![], Some(ty::OutlivesPredicate(r_a, r_b)) => { vec![OutlivesBound::RegionSubRegion(r_b, r_a)] } }, - ty::Predicate::TypeOutlives(ref data) => match data.no_bound_vars() { + ty::PredicateKind::TypeOutlives(ref data) => match data.no_bound_vars() { None => vec![], Some(ty::OutlivesPredicate(ty_a, r_b)) => { let ty_a = infcx.resolve_vars_if_possible(&ty_a); diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index ed30ed5313e5c..11604cc31870f 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -41,14 +41,14 @@ fn normalize_generic_arg_after_erasing_regions<'tcx>( fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { match p { - ty::Predicate::RegionOutlives(..) | ty::Predicate::TypeOutlives(..) => false, - ty::Predicate::Trait(..) - | ty::Predicate::Projection(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => true, + ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, + ty::PredicateKind::Trait(..) + | ty::PredicateKind::Projection(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => true, } } diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index aeb31c2cb7367..58fa927c021e0 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -7,7 +7,8 @@ use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; use rustc_middle::ty::{ - FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance, + self, FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, + Variance, }; use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -140,7 +141,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { self.relate(self_ty, Variance::Invariant, impl_self_ty)?; - self.prove_predicate(Predicate::WellFormed(impl_self_ty)); + self.prove_predicate(ty::PredicateKind::WellFormed(impl_self_ty)); } // In addition to proving the predicates, we have to @@ -154,7 +155,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { // them? This would only be relevant if some input // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... - self.prove_predicate(Predicate::WellFormed(ty)); + self.prove_predicate(ty::PredicateKind::WellFormed(ty)); Ok(()) } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6529d784ad452..a697ae7cb877c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1597,7 +1597,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { obligation.predicate ); match obligation.predicate { - ty::Predicate::Trait(pred, _) => { + ty::PredicateKind::Trait(pred, _) => { associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) .in_definition_order() @@ -1605,7 +1605,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|item| item.def_id), ); } - ty::Predicate::Projection(pred) => { + ty::PredicateKind::Projection(pred) => { // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. let references_self = diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 87a6f119acb09..6ade48b80c8a5 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -206,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligation.predicate ); - if let ty::Predicate::Projection(ref proj_predicate) = obligation.predicate { + if let ty::PredicateKind::Projection(ref proj_predicate) = obligation.predicate { // Given a Projection predicate, we can potentially infer // the complete signature. self.deduce_sig_from_projection(Some(obligation.cause.span), proj_predicate) @@ -526,7 +526,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { all_obligations.push(Obligation::new( cause, self.param_env, - ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( + ty::PredicateKind::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( supplied_ty, closure_body_region, ))), @@ -641,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // where R is the return type we are expecting. This type `T` // will be our output. let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| { - if let ty::Predicate::Projection(ref proj_predicate) = obligation.predicate { + if let ty::PredicateKind::Projection(ref proj_predicate) = obligation.predicate { self.deduce_future_output_from_projection(obligation.cause.span, proj_predicate) } else { None diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 54562cf38addd..8a93b05ac8db0 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -597,7 +597,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); let trait_pred = match obligation.predicate { - ty::Predicate::Trait(trait_pred, _) if traits.contains(&trait_pred.def_id()) => { + ty::PredicateKind::Trait(trait_pred, _) + if traits.contains(&trait_pred.def_id()) => + { if unsize_did == trait_pred.def_id() { let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); if let ty::Tuple(..) = unsize_ty.kind { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 9694ce9450c27..550a236279550 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -644,7 +644,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap() .def_id; let predicate = - ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { + ty::PredicateKind::Projection(ty::Binder::bind(ty::ProjectionPredicate { // `::Output` projection_ty: ty::ProjectionTy { // `T` diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 478a848cf09dd..51d28f7c57c65 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -231,8 +231,10 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let predicate_matches_closure = |p: &'_ Predicate<'tcx>| { let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); match (predicate, p) { - (Predicate::Trait(a, _), Predicate::Trait(b, _)) => relator.relate(a, b).is_ok(), - (Predicate::Projection(a), Predicate::Projection(b)) => { + (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => { + relator.relate(a, b).is_ok() + } + (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => { relator.relate(a, b).is_ok() } _ => predicate == p, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index c4805c54a7d43..64917bf4c9f44 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -575,7 +575,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied()) .filter_map(|obligation| match obligation.predicate { - ty::Predicate::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => { + ty::PredicateKind::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => { let span = predicates .predicates .iter() diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index a254aecf07bab..135e02d6b5fac 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations.push(traits::Obligation::new( cause, self.param_env, - ty::Predicate::WellFormed(method_ty), + ty::PredicateKind::WellFormed(method_ty), )); let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e21db9035e25d..fbe8e7b767511 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -797,21 +797,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // FIXME: do we want to commit to this behavior for param bounds? let bounds = self.param_env.caller_bounds.iter().filter_map(|predicate| match *predicate { - ty::Predicate::Trait(ref trait_predicate, _) => { + ty::PredicateKind::Trait(ref trait_predicate, _) => { match trait_predicate.skip_binder().trait_ref.self_ty().kind { ty::Param(ref p) if *p == param_ty => Some(trait_predicate.to_poly_trait_ref()), _ => None, } } - ty::Predicate::Subtype(..) - | ty::Predicate::Projection(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => None, + ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Projection(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::TypeOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => None, }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index cf26c94418e2d..e0ab25e49224e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -574,7 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut bound_spans = vec![]; let mut collect_type_param_suggestions = |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| { - if let (ty::Param(_), ty::Predicate::Trait(p, _)) = + if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) = (&self_ty.kind, parent_pred) { if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind { @@ -628,7 +628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut format_pred = |pred| { match pred { - ty::Predicate::Projection(pred) => { + ty::PredicateKind::Projection(pred) => { // `::Item = String`. let trait_ref = pred.skip_binder().projection_ty.trait_ref(self.tcx); @@ -646,7 +646,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_span_label(trait_ref.self_ty(), &obligation, &quiet); Some((obligation, trait_ref.self_ty())) } - ty::Predicate::Trait(poly_trait_ref, _) => { + ty::PredicateKind::Trait(poly_trait_ref, _) => { let p = poly_trait_ref.skip_binder().trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); @@ -949,8 +949,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_predicates.iter().all(|(p, _)| match p { // Hide traits if they are present in predicates as they can be fixed without // having to implement them. - ty::Predicate::Trait(t, _) => t.def_id() == info.def_id, - ty::Predicate::Projection(p) => p.item_def_id() == info.def_id, + ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id, + ty::PredicateKind::Projection(p) => p.item_def_id() == info.def_id, _ => false, }) && (type_is_local || info.def_id.is_local()) && self diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d72c74e4188ee..79cb7a7fd0ffa 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2224,7 +2224,7 @@ fn bounds_from_generic_predicates( for (predicate, _) in predicates.predicates { debug!("predicate {:?}", predicate); match predicate { - ty::Predicate::Trait(trait_predicate, _) => { + ty::PredicateKind::Trait(trait_predicate, _) => { let entry = types.entry(trait_predicate.skip_binder().self_ty()).or_default(); let def_id = trait_predicate.skip_binder().def_id(); if Some(def_id) != tcx.lang_items().sized_trait() { @@ -2233,7 +2233,7 @@ fn bounds_from_generic_predicates( entry.push(trait_predicate.skip_binder().def_id()); } } - ty::Predicate::Projection(projection_pred) => { + ty::PredicateKind::Projection(projection_pred) => { projections.push(projection_pred); } _ => {} @@ -2770,7 +2770,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { parent: None, predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map( |&predicate| match predicate { - ty::Predicate::Trait(ref data, _) + ty::PredicateKind::Trait(ref data, _) if data.skip_binder().self_ty().is_param(index) => { // HACK(eddyb) should get the original `Span`. @@ -3379,7 +3379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::Predicate::ConstEvaluatable(def_id, substs), + ty::PredicateKind::ConstEvaluatable(def_id, substs), )); } @@ -3428,7 +3428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::Predicate::WellFormed(ty), + ty::PredicateKind::WellFormed(ty), )); } @@ -3858,17 +3858,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .pending_obligations() .into_iter() .filter_map(move |obligation| match obligation.predicate { - ty::Predicate::Projection(ref data) => { + ty::PredicateKind::Projection(ref data) => { Some((data.to_poly_trait_ref(self.tcx), obligation)) } - ty::Predicate::Trait(ref data, _) => Some((data.to_poly_trait_ref(), obligation)), - ty::Predicate::Subtype(..) => None, - ty::Predicate::RegionOutlives(..) => None, - ty::Predicate::TypeOutlives(..) => None, - ty::Predicate::WellFormed(..) => None, - ty::Predicate::ObjectSafe(..) => None, - ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::ConstEquate(..) => None, + ty::PredicateKind::Trait(ref data, _) => { + Some((data.to_poly_trait_ref(), obligation)) + } + ty::PredicateKind::Subtype(..) => None, + ty::PredicateKind::RegionOutlives(..) => None, + ty::PredicateKind::TypeOutlives(..) => None, + ty::PredicateKind::WellFormed(..) => None, + ty::PredicateKind::ObjectSafe(..) => None, + ty::PredicateKind::ConstEvaluatable(..) => None, + ty::PredicateKind::ConstEquate(..) => None, // N.B., this predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where // `ClosureType` represents some `Closure`. It can't @@ -3877,7 +3879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this closure yet; this is exactly why the other // code is looking for a self type of a unresolved // inference variable. - ty::Predicate::ClosureKind(..) => None, + ty::PredicateKind::ClosureKind(..) => None, }) .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) } @@ -4206,7 +4208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate { + if let ty::PredicateKind::Trait(predicate, _) = error.obligation.predicate { // Collect the argument position for all arguments that could have caused this // `FulfillmentError`. let mut referenced_in = final_arg_types @@ -4253,7 +4255,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::ExprKind::Path(qpath) = &path.kind { if let hir::QPath::Resolved(_, path) = &qpath { for error in errors { - if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate { + if let ty::PredicateKind::Trait(predicate, _) = error.obligation.predicate { // If any of the type arguments in this path segment caused the // `FullfillmentError`, point at its span (#61860). for arg in path @@ -5322,7 +5324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let predicate = - ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { + ty::PredicateKind::Projection(ty::Binder::bind(ty::ProjectionPredicate { projection_ty, ty: expected, })); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b79ac50da8fa3..cb3ee8d1ded0a 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -425,7 +425,7 @@ fn check_type_defn<'tcx, F>( fcx.register_predicate(traits::Obligation::new( cause, fcx.param_env, - ty::Predicate::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs), + ty::PredicateKind::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs), )); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fe3028102c685..c39df5df977ed 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -549,7 +549,9 @@ fn type_param_predicates( icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true)) .into_iter() .filter(|(predicate, _)| match predicate { - ty::Predicate::Trait(ref data, _) => data.skip_binder().self_ty().is_param(index), + ty::PredicateKind::Trait(ref data, _) => { + data.skip_binder().self_ty().is_param(index) + } _ => false, }), ); @@ -994,7 +996,7 @@ fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredi // which will, in turn, reach indirect supertraits. for &(pred, span) in superbounds { debug!("superbound: {:?}", pred); - if let ty::Predicate::Trait(bound, _) = pred { + if let ty::PredicateKind::Trait(bound, _) = pred { tcx.at(span).super_predicates_of(bound.def_id()); } } @@ -1899,7 +1901,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let re_root_empty = tcx.lifetimes.re_root_empty; let predicate = ty::OutlivesPredicate(ty, re_root_empty); predicates.push(( - ty::Predicate::TypeOutlives(ty::Binder::dummy(predicate)), + ty::PredicateKind::TypeOutlives(ty::Binder::dummy(predicate)), span, )); } @@ -1928,7 +1930,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); let pred = ty::Binder::bind(ty::OutlivesPredicate(ty, region)); - predicates.push((ty::Predicate::TypeOutlives(pred), lifetime.span)) + predicates.push((ty::PredicateKind::TypeOutlives(pred), lifetime.span)) } } } @@ -1945,7 +1947,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat }; let pred = ty::Binder::bind(ty::OutlivesPredicate(r1, r2)); - (ty::Predicate::RegionOutlives(pred), span) + (ty::PredicateKind::RegionOutlives(pred), span) })) } @@ -2116,7 +2118,7 @@ fn predicates_from_bound<'tcx>( hir::GenericBound::Outlives(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region)); - vec![(ty::Predicate::TypeOutlives(pred), lifetime.span)] + vec![(ty::PredicateKind::TypeOutlives(pred), lifetime.span)] } } } diff --git a/src/librustc_typeck/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs index 07ff3bc85cc19..c1be430b93e98 100644 --- a/src/librustc_typeck/constrained_generic_params.rs +++ b/src/librustc_typeck/constrained_generic_params.rs @@ -180,7 +180,7 @@ pub fn setup_constraining_predicates<'tcx>( changed = false; for j in i..predicates.len() { - if let ty::Predicate::Projection(ref poly_projection) = predicates[j].0 { + if let ty::PredicateKind::Projection(ref poly_projection) = predicates[j].0 { // Note that we can skip binder here because the impl // trait ref never contains any late-bound regions. let projection = poly_projection.skip_binder(); diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index 919bcc9943d48..89d63107a9c29 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -204,7 +204,7 @@ fn unconstrained_parent_impl_substs<'tcx>( // the functions in `cgp` add the constrained parameters to a list of // unconstrained parameters. for (predicate, _) in impl_generic_predicates.predicates.iter() { - if let ty::Predicate::Projection(proj) = predicate { + if let ty::PredicateKind::Projection(proj) = predicate { let projection_ty = proj.skip_binder().projection_ty; let projected_ty = proj.skip_binder().ty; @@ -374,7 +374,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: &ty::Predicate<'t _ if predicate.is_global() => (), // We allow specializing on explicitly marked traits with no associated // items. - ty::Predicate::Trait(pred, hir::Constness::NotConst) => { + ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => { if !matches!( trait_predicate_kind(tcx, predicate), Some(TraitSpecializationKind::Marker) @@ -402,18 +402,18 @@ fn trait_predicate_kind<'tcx>( predicate: &ty::Predicate<'tcx>, ) -> Option { match predicate { - ty::Predicate::Trait(pred, hir::Constness::NotConst) => { + ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => { Some(tcx.trait_def(pred.def_id()).specialization_kind) } - ty::Predicate::Trait(_, hir::Constness::Const) - | ty::Predicate::RegionOutlives(_) - | ty::Predicate::TypeOutlives(_) - | ty::Predicate::Projection(_) - | ty::Predicate::WellFormed(_) - | ty::Predicate::Subtype(_) - | ty::Predicate::ObjectSafe(_) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => None, + ty::PredicateKind::Trait(_, hir::Constness::Const) + | ty::PredicateKind::RegionOutlives(_) + | ty::PredicateKind::TypeOutlives(_) + | ty::PredicateKind::Projection(_) + | ty::PredicateKind::WellFormed(_) + | ty::PredicateKind::Subtype(_) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => None, } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 66daf0e7f7d9d..bc8d25f953820 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -30,7 +30,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { // process predicates and convert to `RequiredPredicates` entry, see below for &(predicate, span) in predicates.predicates { match predicate { - ty::Predicate::TypeOutlives(predicate) => { + ty::PredicateKind::TypeOutlives(predicate) => { let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder(); insert_outlives_predicate( tcx, @@ -41,7 +41,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { ) } - ty::Predicate::RegionOutlives(predicate) => { + ty::PredicateKind::RegionOutlives(predicate) => { let OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder(); insert_outlives_predicate( tcx, @@ -52,14 +52,14 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { ) } - ty::Predicate::Trait(..) - | ty::Predicate::Projection(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) - | ty::Predicate::ConstEquate(..) => (), + ty::PredicateKind::Trait(..) + | ty::PredicateKind::Projection(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => (), } } diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index a49d8e5ed0f0a..d88fda3550500 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -31,8 +31,8 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate let mut pred: Vec = predicates .iter() .map(|(out_pred, _)| match out_pred { - ty::Predicate::RegionOutlives(p) => p.to_string(), - ty::Predicate::TypeOutlives(p) => p.to_string(), + ty::PredicateKind::RegionOutlives(p) => p.to_string(), + ty::PredicateKind::TypeOutlives(p) => p.to_string(), err => bug!("unexpected predicate {:?}", err), }) .collect(); @@ -84,13 +84,13 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CratePredica let predicates = &*tcx.arena.alloc_from_iter(set.iter().filter_map( |(ty::OutlivesPredicate(kind1, region2), &span)| match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::Predicate::TypeOutlives(ty::Binder::bind(ty::OutlivesPredicate( + ty::PredicateKind::TypeOutlives(ty::Binder::bind(ty::OutlivesPredicate( ty1, region2, ))), span, )), GenericArgKind::Lifetime(region1) => Some(( - ty::Predicate::RegionOutlives(ty::Binder::bind(ty::OutlivesPredicate( + ty::PredicateKind::RegionOutlives(ty::Binder::bind(ty::OutlivesPredicate( region1, region2, ))), span, diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 144c1699a3ca8..ff05c4e583269 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -316,10 +316,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { pred: ty::Predicate<'tcx>, ) -> FxHashSet { let regions = match pred { - ty::Predicate::Trait(poly_trait_pred, _) => { + ty::PredicateKind::Trait(poly_trait_pred, _) => { tcx.collect_referenced_late_bound_regions(&poly_trait_pred) } - ty::Predicate::Projection(poly_proj_pred) => { + ty::PredicateKind::Projection(poly_proj_pred) => { tcx.collect_referenced_late_bound_regions(&poly_proj_pred) } _ => return FxHashSet::default(), @@ -466,7 +466,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .filter(|p| { !orig_bounds.contains(p) || match p { - ty::Predicate::Trait(pred, _) => pred.def_id() == sized_trait, + ty::PredicateKind::Trait(pred, _) => pred.def_id() == sized_trait, _ => false, } }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c130ed3f46dbb..002af495ff226 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -481,20 +481,18 @@ impl Clean for hir::WherePredicate<'_> { impl<'a> Clean> for ty::Predicate<'a> { fn clean(&self, cx: &DocContext<'_>) -> Option { - use rustc_middle::ty::Predicate; - match *self { - Predicate::Trait(ref pred, _) => Some(pred.clean(cx)), - Predicate::Subtype(ref pred) => Some(pred.clean(cx)), - Predicate::RegionOutlives(ref pred) => pred.clean(cx), - Predicate::TypeOutlives(ref pred) => pred.clean(cx), - Predicate::Projection(ref pred) => Some(pred.clean(cx)), + ty::PredicateKind::Trait(ref pred, _) => Some(pred.clean(cx)), + ty::PredicateKind::Subtype(ref pred) => Some(pred.clean(cx)), + ty::PredicateKind::RegionOutlives(ref pred) => pred.clean(cx), + ty::PredicateKind::TypeOutlives(ref pred) => pred.clean(cx), + ty::PredicateKind::Projection(ref pred) => Some(pred.clean(cx)), - Predicate::WellFormed(..) - | Predicate::ObjectSafe(..) - | Predicate::ClosureKind(..) - | Predicate::ConstEvaluatable(..) - | Predicate::ConstEquate(..) => panic!("not user writable"), + ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => panic!("not user writable"), } } } @@ -765,7 +763,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx if let ty::Param(param) = outlives.skip_binder().0.kind { return Some(param.index); } - } else if let ty::Predicate::Projection(p) = p { + } else if let ty::PredicateKind::Projection(p) = p { if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().kind { projection = Some(p); return Some(param.index); @@ -1663,7 +1661,7 @@ impl<'tcx> Clean for Ty<'tcx> { .filter_map(|predicate| { let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() { tr - } else if let ty::Predicate::TypeOutlives(pred) = *predicate { + } else if let ty::PredicateKind::TypeOutlives(pred) = *predicate { // these should turn up at the end if let Some(r) = pred.skip_binder().1.clean(cx) { regions.push(GenericBound::Outlives(r)); @@ -1684,7 +1682,7 @@ impl<'tcx> Clean for Ty<'tcx> { .predicates .iter() .filter_map(|pred| { - if let ty::Predicate::Projection(proj) = *pred { + if let ty::PredicateKind::Projection(proj) = *pred { let proj = proj.skip_binder(); if proj.projection_ty.trait_ref(cx.tcx) == *trait_ref.skip_binder() diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 1404d45ea8938..cc91c50346180 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -141,7 +141,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) .predicates .iter() .filter_map(|(pred, _)| { - if let ty::Predicate::Trait(ref pred, _) = *pred { + if let ty::PredicateKind::Trait(ref pred, _) = *pred { if pred.skip_binder().trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 704a95ec0a090..2c2965433fd0e 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -3,7 +3,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Opaque, Predicate::Trait, ToPolyTraitRef}; +use rustc_middle::ty::{Opaque, PredicateKind::Trait, ToPolyTraitRef}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 626427c15ecf5..79c21d9bc0a64 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Predicate, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -1497,7 +1497,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { // one of the associated types must be Self for predicate in cx.tcx.predicates_of(def_id).predicates { match predicate { - (Predicate::Projection(poly_projection_predicate), _) => { + (ty::PredicateKind::Projection(poly_projection_predicate), _) => { let binder = poly_projection_predicate.ty(); let associated_type = binder.skip_binder(); diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index ed48ab548978c..8f94f143bae71 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter().copied()) .filter(|p| !p.is_global()) .filter_map(|obligation| { - if let ty::Predicate::Trait(poly_trait_ref, _) = obligation.predicate { + if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate { if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars() { return None; diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 438a9f42ccd23..3f5693d7e6809 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1299,7 +1299,7 @@ pub fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> boo ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.predicates_of(*def_id).predicates { - if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate { + if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate { if must_use_attr(&cx.tcx.get_attrs(poly_trait_predicate.skip_binder().trait_ref.def_id)).is_some() { return true; } From 2722522fac927b9bd7c512f993e63afd3754cf4e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 21:09:57 +0200 Subject: [PATCH 083/695] rename `Predicate` to `PredicateKind`, introduce alias --- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/utils/mod.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 704a95ec0a090..2c2965433fd0e 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -3,7 +3,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Opaque, Predicate::Trait, ToPolyTraitRef}; +use rustc_middle::ty::{Opaque, PredicateKind::Trait, ToPolyTraitRef}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 626427c15ecf5..79c21d9bc0a64 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Predicate, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{sym, SymbolStr}; @@ -1497,7 +1497,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { // one of the associated types must be Self for predicate in cx.tcx.predicates_of(def_id).predicates { match predicate { - (Predicate::Projection(poly_projection_predicate), _) => { + (ty::PredicateKind::Projection(poly_projection_predicate), _) => { let binder = poly_projection_predicate.ty(); let associated_type = binder.skip_binder(); diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index ed48ab548978c..8f94f143bae71 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter().copied()) .filter(|p| !p.is_global()) .filter_map(|obligation| { - if let ty::Predicate::Trait(poly_trait_ref, _) = obligation.predicate { + if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate { if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars() { return None; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 438a9f42ccd23..3f5693d7e6809 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1299,7 +1299,7 @@ pub fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> boo ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.predicates_of(*def_id).predicates { - if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate { + if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate { if must_use_attr(&cx.tcx.get_attrs(poly_trait_predicate.skip_binder().trait_ref.def_id)).is_some() { return true; } From ecd0a67b01e13d7a80d2f64bbfa5da1e568367e5 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 20 May 2020 13:23:51 +0300 Subject: [PATCH 084/695] Make match_wild_err_arm pedantic, and update help messages --- clippy_lints/src/lib.rs | 3 +-- clippy_lints/src/matches.rs | 6 +++--- src/lintlist/mod.rs | 2 +- tests/ui/match_wild_err_arm.stderr | 8 ++++---- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4d4fff883b3e2..057d39d4c8252 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1141,6 +1141,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::MATCH_BOOL), LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), + LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::SINGLE_MATCH_ELSE), LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), @@ -1285,7 +1286,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), LintId::of(&matches::MATCH_SINGLE_BINDING), - LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::SINGLE_MATCH), LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), @@ -1476,7 +1476,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), - LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 4106e5013b947..94380acfcfd4c 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -168,7 +168,7 @@ declare_clippy_lint! { /// **What it does:** Checks for arm which matches all errors with `Err(_)` /// and take drastic actions like `panic!`. /// - /// **Why is this bad?** It is generally a bad practice, just like + /// **Why is this bad?** It is generally a bad practice, similar to /// catching all exceptions in java with `catch(Exception)` /// /// **Known problems:** None. @@ -182,7 +182,7 @@ declare_clippy_lint! { /// } /// ``` pub MATCH_WILD_ERR_ARM, - style, + pedantic, "a `match` with `Err(_)` arm and take drastic actions" } @@ -711,7 +711,7 @@ fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) arm.pat.span, &format!("`Err({})` matches all errors", &ident_bind_name), None, - "match each error separately or use the error output", + "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable", ); } } diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0bf46491d31d0..8211a57b56439 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1195,7 +1195,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "match_wild_err_arm", - group: "style", + group: "pedantic", desc: "a `match` with `Err(_)` arm and take drastic actions", deprecation: None, module: "matches", diff --git a/tests/ui/match_wild_err_arm.stderr b/tests/ui/match_wild_err_arm.stderr index 20d4c933418b7..6a2a02987dea7 100644 --- a/tests/ui/match_wild_err_arm.stderr +++ b/tests/ui/match_wild_err_arm.stderr @@ -5,7 +5,7 @@ LL | Err(_) => panic!("err"), | ^^^^^^ | = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` - = note: match each error separately or use the error output + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:17:9 @@ -13,7 +13,7 @@ error: `Err(_)` matches all errors LL | Err(_) => panic!(), | ^^^^^^ | - = note: match each error separately or use the error output + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:23:9 @@ -21,7 +21,7 @@ error: `Err(_)` matches all errors LL | Err(_) => { | ^^^^^^ | - = note: match each error separately or use the error output + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_e)` matches all errors --> $DIR/match_wild_err_arm.rs:31:9 @@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors LL | Err(_e) => panic!(), | ^^^^^^^ | - = note: match each error separately or use the error output + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: aborting due to 4 previous errors From 034c25f33e496f602edebd845ddb4f940ac176cf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 7 May 2020 10:12:19 +0000 Subject: [PATCH 085/695] make `to_predicate` take a `tcx` argument --- src/librustc_infer/traits/engine.rs | 2 +- src/librustc_infer/traits/util.rs | 4 +- src/librustc_middle/ty/mod.rs | 18 ++--- src/librustc_middle/ty/sty.rs | 4 +- .../traits/error_reporting/mod.rs | 14 ++-- .../traits/error_reporting/suggestions.rs | 73 ++++++++++--------- src/librustc_trait_selection/traits/mod.rs | 4 +- .../traits/object_safety.rs | 6 +- .../traits/project.rs | 11 +-- src/librustc_trait_selection/traits/select.rs | 6 +- src/librustc_trait_selection/traits/util.rs | 9 ++- src/librustc_trait_selection/traits/wf.rs | 6 +- src/librustc_ty/ty.rs | 2 +- src/librustc_typeck/astconv.rs | 8 +- src/librustc_typeck/check/autoderef.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 7 +- src/librustc_typeck/collect.rs | 8 +- src/librustdoc/clean/blanket_impl.rs | 2 +- 22 files changed, 102 insertions(+), 92 deletions(-) diff --git a/src/librustc_infer/traits/engine.rs b/src/librustc_infer/traits/engine.rs index a95257ba6820a..2710debea9478 100644 --- a/src/librustc_infer/traits/engine.rs +++ b/src/librustc_infer/traits/engine.rs @@ -33,7 +33,7 @@ pub trait TraitEngine<'tcx>: 'tcx { cause, recursion_depth: 0, param_env, - predicate: trait_ref.without_const().to_predicate(), + predicate: trait_ref.without_const().to_predicate(infcx.tcx), }, ); } diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 400fe4d1321ca..b9cafc530cd47 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -99,14 +99,14 @@ pub fn elaborate_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Elaborator<'tcx> { - elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate())) + elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx))) } pub fn elaborate_trait_refs<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator>, ) -> Elaborator<'tcx> { - let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()); + let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate(tcx)); elaborate_predicates(tcx, predicates) } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index e3aeb242dc034..16a44328b82fa 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1295,11 +1295,11 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { } pub trait ToPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx>; + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; } impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { - fn to_predicate(&self) -> Predicate<'tcx> { + fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { ty::PredicateKind::Trait( ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value }), self.constness, @@ -1308,7 +1308,7 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { } impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { - fn to_predicate(&self) -> Predicate<'tcx> { + fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { ty::PredicateKind::Trait( ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }), self.constness, @@ -1317,31 +1317,31 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { } impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { - fn to_predicate(&self) -> Predicate<'tcx> { + fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness) } } impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> { - fn to_predicate(&self) -> Predicate<'tcx> { + fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness) } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { + fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { PredicateKind::RegionOutlives(*self) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { + fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { PredicateKind::TypeOutlives(*self) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { + fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { PredicateKind::Projection(*self) } } @@ -1619,7 +1619,7 @@ pub struct ConstnessAnd { pub value: T, } -// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate()` to ensure that +// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate(tcx)` to ensure that // the constness of trait bounds is being propagated correctly. pub trait WithConstness: Sized { #[inline] diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 8962b243911b2..1e4aaa6054525 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -612,7 +612,7 @@ impl<'tcx> Binder> { use crate::ty::ToPredicate; match *self.skip_binder() { ExistentialPredicate::Trait(tr) => { - Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate() + Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx) } ExistentialPredicate::Projection(p) => { ty::PredicateKind::Projection(Binder(p.with_self_ty(tcx, self_ty))) @@ -620,7 +620,7 @@ impl<'tcx> Binder> { ExistentialPredicate::AutoTrait(did) => { let trait_ref = Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) }); - trait_ref.without_const().to_predicate() + trait_ref.without_const().to_predicate(tcx) } } } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index ac119a0c3d811..f997fbadd89fc 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -308,7 +308,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "{}", message.unwrap_or_else(|| format!( "the trait bound `{}` is not satisfied{}", - trait_ref.without_const().to_predicate(), + trait_ref.without_const().to_predicate(tcx), post_message, )) ); @@ -1021,13 +1021,13 @@ trait InferCtxtPrivExt<'tcx> { fn note_obligation_cause( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ); fn suggest_unsized_bound_if_applicable( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ); @@ -1390,7 +1390,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> PredicateObligation<'tcx> { let new_trait_ref = ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; - Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) + Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate(self.tcx)) } fn maybe_report_ambiguity( @@ -1629,7 +1629,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let obligation = Obligation::new( ObligationCause::dummy(), param_env, - cleaned_pred.without_const().to_predicate(), + cleaned_pred.without_const().to_predicate(selcx.tcx()), ); self.predicate_may_hold(&obligation) @@ -1638,7 +1638,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { fn note_obligation_cause( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ) { // First, attempt to add note to this error with an async-await-specific @@ -1656,7 +1656,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_unsized_bound_if_applicable( &self, - err: &mut DiagnosticBuilder<'_>, + err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ) { if let ( diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 5baaf838caa72..cbc93278353be 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -38,14 +38,14 @@ pub trait InferCtxtExt<'tcx> { fn suggest_restricting_param_bound( &self, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::PolyTraitRef<'_>, + trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, ); fn suggest_borrow_on_unsized_slice( &self, code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, ); fn get_closure_name( @@ -66,7 +66,7 @@ pub trait InferCtxtExt<'tcx> { fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::Binder>, points_at_arg: bool, has_custom_message: bool, @@ -75,14 +75,14 @@ pub trait InferCtxtExt<'tcx> { fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::Binder>, ); fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::Binder>, points_at_arg: bool, ); @@ -90,7 +90,7 @@ pub trait InferCtxtExt<'tcx> { fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, span: Span, trait_ref: &ty::Binder>, ); @@ -99,7 +99,7 @@ pub trait InferCtxtExt<'tcx> { fn suggest_impl_trait( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, trait_ref: &ty::Binder>, @@ -107,7 +107,7 @@ pub trait InferCtxtExt<'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, ); @@ -138,11 +138,11 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, interior_or_upvar_span: GeneratorInteriorOrUpvar, interior_extra_info: Option<(Option, Span, Option, Option)>, - inner_generator_body: Option<&hir::Body<'_>>, + inner_generator_body: Option<&hir::Body<'tcx>>, outer_generator: Option, - trait_ref: ty::TraitRef<'_>, + trait_ref: ty::TraitRef<'tcx>, target_ty: Ty<'tcx>, - tables: &ty::TypeckTables<'_>, + tables: &ty::TypeckTables<'tcx>, obligation: &PredicateObligation<'tcx>, next_code: Option<&ObligationCauseCode<'tcx>>, ); @@ -183,12 +183,13 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, St /// it can also be an `impl Trait` param that needs to be decomposed to a type /// param for cleaner code. fn suggest_restriction( - generics: &hir::Generics<'_>, + tcx: TyCtxt<'tcx>, + generics: &hir::Generics<'tcx>, msg: &str, err: &mut DiagnosticBuilder<'_>, fn_sig: Option<&hir::FnSig<'_>>, projection: Option<&ty::ProjectionTy<'_>>, - trait_ref: ty::PolyTraitRef<'_>, + trait_ref: ty::PolyTraitRef<'tcx>, super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>, ) { // When we are dealing with a trait, `super_traits` will be `Some`: @@ -243,7 +244,7 @@ fn suggest_restriction( // FIXME: modify the `trait_ref` instead of string shenanigans. // Turn `::Bar: Qux` into `::Bar: Qux`. - let pred = trait_ref.without_const().to_predicate().to_string(); + let pred = trait_ref.without_const().to_predicate(tcx).to_string(); let pred = pred.replace(&impl_trait_str, &type_param_name); let mut sugg = vec![ match generics @@ -285,9 +286,10 @@ fn suggest_restriction( } else { // Trivial case: `T` needs an extra bound: `T: Bound`. let (sp, suggestion) = match super_traits { - None => { - predicate_constraint(generics, trait_ref.without_const().to_predicate().to_string()) - } + None => predicate_constraint( + generics, + trait_ref.without_const().to_predicate(tcx).to_string(), + ), Some((ident, bounds)) => match bounds { [.., bound] => ( bound.span().shrink_to_hi(), @@ -313,7 +315,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_restricting_param_bound( &self, mut err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::PolyTraitRef<'_>, + trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, ) { let self_ty = trait_ref.self_ty(); @@ -336,6 +338,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( + self.tcx, &generics, "`Self`", err, @@ -355,7 +358,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( - &generics, "`Self`", err, None, projection, trait_ref, None, + self.tcx, &generics, "`Self`", err, None, projection, trait_ref, None, ); return; } @@ -375,6 +378,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }) if projection.is_some() => { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( + self.tcx, &generics, "the associated type", err, @@ -393,6 +397,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }) if projection.is_some() => { // Missing restriction on associated type of type parameter (unmet projection). suggest_restriction( + self.tcx, &generics, "the associated type", err, @@ -450,7 +455,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_borrow_on_unsized_slice( &self, code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, ) { if let &ObligationCauseCode::VariableType(hir_id) = code { let parent_node = self.tcx.hir().get_parent_node(hir_id); @@ -601,7 +606,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::Binder>, points_at_arg: bool, has_custom_message: bool, @@ -624,7 +629,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let new_obligation = Obligation::new( ObligationCause::dummy(), param_env, - new_trait_ref.without_const().to_predicate(), + new_trait_ref.without_const().to_predicate(self.tcx), ); if self.predicate_must_hold_modulo_regions(&new_obligation) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -673,7 +678,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::Binder>, ) { let trait_ref = trait_ref.skip_binder(); @@ -735,7 +740,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::Binder>, points_at_arg: bool, ) { @@ -806,7 +811,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, span: Span, trait_ref: &ty::Binder>, ) { @@ -852,7 +857,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// emitted. fn suggest_impl_trait( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, trait_ref: &ty::Binder>, @@ -1048,7 +1053,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, ) { match obligation.cause.code.peel_derives() { @@ -1430,11 +1435,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, interior_or_upvar_span: GeneratorInteriorOrUpvar, interior_extra_info: Option<(Option, Span, Option, Option)>, - inner_generator_body: Option<&hir::Body<'_>>, + inner_generator_body: Option<&hir::Body<'tcx>>, outer_generator: Option, - trait_ref: ty::TraitRef<'_>, + trait_ref: ty::TraitRef<'tcx>, target_ty: Ty<'tcx>, - tables: &ty::TypeckTables<'_>, + tables: &ty::TypeckTables<'tcx>, obligation: &PredicateObligation<'tcx>, next_code: Option<&ObligationCauseCode<'tcx>>, ) { @@ -1788,7 +1793,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.note(&format!("required because it appears within the type `{}`", ty)); obligated_types.push(ty); - let parent_predicate = parent_trait_ref.without_const().to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); if !self.is_recursive_obligation(obligated_types, &data.parent_code) { self.note_obligation_cause_code( err, @@ -1805,7 +1810,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { parent_trait_ref.print_only_trait_path(), parent_trait_ref.skip_binder().self_ty() )); - let parent_predicate = parent_trait_ref.without_const().to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); self.note_obligation_cause_code( err, &parent_predicate, @@ -1815,7 +1820,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } ObligationCauseCode::DerivedObligation(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - let parent_predicate = parent_trait_ref.without_const().to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); self.note_obligation_cause_code( err, &parent_predicate, @@ -2061,7 +2066,7 @@ impl NextTypeParamName for &[hir::GenericParam<'_>] { } fn suggest_trait_object_return_type_alternatives( - err: &mut DiagnosticBuilder<'tcx>, + err: &mut DiagnosticBuilder<'_>, ret_ty: Span, trait_obj: &str, is_object_safe: bool, diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 99d434c5c9292..f67669769a10d 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -143,7 +143,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( param_env, cause: ObligationCause::misc(span, hir::CRATE_HIR_ID), recursion_depth: 0, - predicate: trait_ref.without_const().to_predicate(), + predicate: trait_ref.without_const().to_predicate(infcx.tcx), }; let result = infcx.predicate_must_hold_modulo_regions(&obligation); @@ -557,7 +557,7 @@ fn type_implements_trait<'tcx>( cause: ObligationCause::dummy(), param_env, recursion_depth: 0, - predicate: trait_ref.without_const().to_predicate(), + predicate: trait_ref.without_const().to_predicate(tcx), }; tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) } diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index bb727055d03fb..4839a25d85fc9 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -636,7 +636,7 @@ fn receiver_is_dispatchable<'tcx>( substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), } .without_const() - .to_predicate(); + .to_predicate(tcx); // U: Trait let trait_predicate = { @@ -649,7 +649,7 @@ fn receiver_is_dispatchable<'tcx>( } }); - ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate() + ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx) }; let caller_bounds: Vec> = param_env @@ -672,7 +672,7 @@ fn receiver_is_dispatchable<'tcx>( substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), } .without_const() - .to_predicate(); + .to_predicate(tcx); Obligation::new(ObligationCause::dummy(), param_env, predicate) }; diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 54b064359dcbd..79b6ac3f7ad09 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -432,7 +432,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( }); let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var }); let obligation = - Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate()); + Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate(tcx)); obligations.push(obligation); ty_var }) @@ -722,7 +722,7 @@ fn get_paranoid_cache_value_obligation<'a, 'tcx>( cause, recursion_depth: depth, param_env, - predicate: trait_ref.without_const().to_predicate(), + predicate: trait_ref.without_const().to_predicate(infcx.tcx), } } @@ -757,7 +757,7 @@ fn normalize_to_error<'a, 'tcx>( cause, recursion_depth: depth, param_env, - predicate: trait_ref.without_const().to_predicate(), + predicate: trait_ref.without_const().to_predicate(selcx.tcx()), }; let tcx = selcx.infcx().tcx; let def_id = projection_ty.item_def_id; @@ -1158,8 +1158,9 @@ fn confirm_object_candidate<'cx, 'tcx>( object_ty ), }; - let env_predicates = - data.projection_bounds().map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate()); + let env_predicates = data + .projection_bounds() + .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate(selcx.tcx())); let env_predicate = { let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 02da6033a0064..2aae0f2703152 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -3031,7 +3031,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause, obligation.recursion_depth + 1, obligation.param_env, - ty::Binder::bind(outlives).to_predicate(), + ty::Binder::bind(outlives).to_predicate(tcx), )); } @@ -3074,12 +3074,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tcx.require_lang_item(lang_items::SizedTraitLangItem, None), tcx.mk_substs_trait(source, &[]), ); - nested.push(predicate_to_obligation(tr.without_const().to_predicate())); + nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx))); // If the type is `Foo + 'a`, ensure that the type // being cast to `Foo + 'a` outlives `'a`: let outlives = ty::OutlivesPredicate(source, r); - nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate())); + nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate(tcx))); } // `[T; n]` -> `[T]` diff --git a/src/librustc_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs index eff73cf4a2d8a..f2d3f0e1116e2 100644 --- a/src/librustc_trait_selection/traits/util.rs +++ b/src/librustc_trait_selection/traits/util.rs @@ -97,7 +97,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { let tcx = self.tcx; let trait_ref = item.trait_ref(); - let pred = trait_ref.without_const().to_predicate(); + let pred = trait_ref.without_const().to_predicate(tcx); debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); @@ -110,7 +110,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { // Don't recurse if this trait alias is already on the stack for the DFS search. let anon_pred = anonymize_predicate(tcx, &pred); if item.path.iter().rev().skip(1).any(|(tr, _)| { - anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred + anonymize_predicate(tcx, &tr.without_const().to_predicate(tcx)) == anon_pred }) { return false; } @@ -234,6 +234,7 @@ pub fn predicates_for_generics<'tcx>( } pub fn predicate_for_trait_ref<'tcx>( + tcx: TyCtxt<'tcx>, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, trait_ref: ty::TraitRef<'tcx>, @@ -243,7 +244,7 @@ pub fn predicate_for_trait_ref<'tcx>( cause, param_env, recursion_depth, - predicate: trait_ref.without_const().to_predicate(), + predicate: trait_ref.without_const().to_predicate(tcx), } } @@ -258,7 +259,7 @@ pub fn predicate_for_trait_def( ) -> PredicateObligation<'tcx> { let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) }; - predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) + predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth) } /// Casts a trait reference into a reference to one of its super diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index b1b50eb2331e2..a6f4819277c20 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -292,7 +292,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.compute_trait_ref(&trait_ref, Elaborate::None); if !data.has_escaping_bound_vars() { - let predicate = trait_ref.without_const().to_predicate(); + let predicate = trait_ref.without_const().to_predicate(self.infcx.tcx); let cause = self.cause(traits::ProjectionWf(data)); self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); } @@ -323,7 +323,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, self.param_env, - trait_ref.without_const().to_predicate(), + trait_ref.without_const().to_predicate(self.infcx.tcx), )); } } @@ -610,7 +610,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, self.param_env, - outlives.to_predicate(), + outlives.to_predicate(self.infcx.tcx), )); } } diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 1aa11a761c821..3da5da2d9efb8 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -61,7 +61,7 @@ fn sized_constraint_for_ty<'tcx>( substs: tcx.mk_substs_trait(ty, &[]), }) .without_const() - .to_predicate(); + .to_predicate(tcx); let predicates = tcx.predicates_of(adtdef.did).predicates; if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a697ae7cb877c..f8144d4aade4e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -3042,7 +3042,7 @@ impl<'tcx> Bounds<'tcx> { def_id: sized, substs: tcx.mk_substs_trait(param_ty, &[]), }); - (trait_ref.without_const().to_predicate(), span) + (trait_ref.without_const().to_predicate(tcx), span) }) }); @@ -3057,16 +3057,16 @@ impl<'tcx> Bounds<'tcx> { // or it's a generic associated type that deliberately has escaping bound vars. let region_bound = ty::fold::shift_region(tcx, region_bound, 1); let outlives = ty::OutlivesPredicate(param_ty, region_bound); - (ty::Binder::bind(outlives).to_predicate(), span) + (ty::Binder::bind(outlives).to_predicate(tcx), span) }) .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { - let predicate = bound_trait_ref.with_constness(constness).to_predicate(); + let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); (predicate, span) })) .chain( self.projection_bounds .iter() - .map(|&(projection, span)| (projection.to_predicate(), span)), + .map(|&(projection, span)| (projection.to_predicate(tcx), span)), ), ) .collect() diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index ae6c1738da77d..8ca0861090605 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -125,7 +125,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let obligation = traits::Obligation::new( cause.clone(), self.param_env, - trait_ref.without_const().to_predicate(), + trait_ref.without_const().to_predicate(tcx), ); if !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 135e02d6b5fac..d1da0bbda540a 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -324,7 +324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, self.param_env, - poly_trait_ref.without_const().to_predicate(), + poly_trait_ref.without_const().to_predicate(self.tcx), ); // Now we want to know if this can be matched diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index fbe8e7b767511..f1a1c48da166a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1374,7 +1374,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } TraitCandidate(trait_ref) => { - let predicate = trait_ref.without_const().to_predicate(); + let predicate = trait_ref.without_const().to_predicate(self.tcx); let obligation = traits::Obligation::new(cause, self.param_env, predicate); if !self.predicate_may_hold(&obligation) { result = ProbeResult::NoMatch; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index e0ab25e49224e..321cc7a3c4bf5 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -58,7 +58,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, self.param_env, - poly_trait_ref.without_const().to_predicate(), + poly_trait_ref.without_const().to_predicate(tcx), ); self.predicate_may_hold(&obligation) }) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 79cb7a7fd0ffa..b9055722bb571 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1458,7 +1458,7 @@ fn check_fn<'a, 'tcx>( inherited.register_predicate(traits::Obligation::new( cause, param_env, - trait_ref.without_const().to_predicate(), + trait_ref.without_const().to_predicate(tcx), )); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index cb3ee8d1ded0a..aa3865059392f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -1174,8 +1174,11 @@ fn receiver_is_implemented( substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), }; - let obligation = - traits::Obligation::new(cause, fcx.param_env, trait_ref.without_const().to_predicate()); + let obligation = traits::Obligation::new( + cause, + fcx.param_env, + trait_ref.without_const().to_predicate(fcx.tcx), + ); if fcx.predicate_must_hold_modulo_regions(&obligation) { true diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c39df5df977ed..529c9f9f50508 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -528,7 +528,7 @@ fn type_param_predicates( if param_id == item_hir_id { let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id); extend = - Some((identity_trait_ref.without_const().to_predicate(), item.span)); + Some((identity_trait_ref.without_const().to_predicate(tcx), item.span)); } generics } @@ -1657,7 +1657,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { let span = tcx.sess.source_map().guess_head_span(tcx.def_span(def_id)); result.predicates = tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(), + ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(tcx), span, )))); } @@ -1832,7 +1832,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { predicates.push(( - trait_ref.to_poly_trait_ref().without_const().to_predicate(), + trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx), tcx.def_span(def_id), )); } @@ -1855,7 +1855,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat hir::GenericBound::Outlives(lt) => { let bound = AstConv::ast_region_to_region(&icx, <, None); let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound)); - predicates.push((outlives.to_predicate(), lt.span)); + predicates.push((outlives.to_predicate(tcx), lt.span)); } _ => bug!(), }); diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index d987505e42735..3d2785541beea 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -65,7 +65,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { match infcx.evaluate_obligation(&traits::Obligation::new( cause, param_env, - trait_ref.without_const().to_predicate(), + trait_ref.without_const().to_predicate(infcx.tcx), )) { Ok(eval_result) => eval_result.may_apply(), Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no From f3164790bdea9ae4f23631f78a4c52dc1b3bdf06 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 22:06:41 +0200 Subject: [PATCH 086/695] introduce newtype'd `Predicate<'tcx>` --- .../infer/canonical/query_response.rs | 11 ++- src/librustc_infer/infer/combine.rs | 14 ++-- src/librustc_infer/infer/outlives/mod.rs | 2 +- src/librustc_infer/infer/sub.rs | 5 +- src/librustc_infer/traits/util.rs | 34 ++++++--- src/librustc_lint/builtin.rs | 6 +- src/librustc_lint/unused.rs | 4 +- src/librustc_middle/ty/codec.rs | 5 +- src/librustc_middle/ty/context.rs | 9 ++- src/librustc_middle/ty/mod.rs | 53 +++++++++---- src/librustc_middle/ty/print/pretty.rs | 4 +- src/librustc_middle/ty/structural_impls.rs | 16 ++-- src/librustc_middle/ty/sty.rs | 1 + .../borrow_check/diagnostics/region_errors.rs | 2 +- .../borrow_check/type_check/mod.rs | 14 ++-- .../transform/qualify_min_const_fn.rs | 4 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_trait_selection/opaque_types.rs | 4 +- .../traits/auto_trait.rs | 17 +++-- .../traits/error_reporting/mod.rs | 21 +++--- .../traits/error_reporting/suggestions.rs | 2 +- .../traits/fulfill.rs | 4 +- src/librustc_trait_selection/traits/mod.rs | 2 +- .../traits/object_safety.rs | 29 +++---- .../traits/project.rs | 6 +- .../traits/query/type_op/prove_predicate.rs | 2 +- src/librustc_trait_selection/traits/select.rs | 11 ++- src/librustc_trait_selection/traits/wf.rs | 30 +++++--- src/librustc_traits/chalk/lowering.rs | 75 ++++++++++--------- .../implied_outlives_bounds.rs | 2 +- .../normalize_erasing_regions.rs | 2 +- src/librustc_traits/type_op.rs | 10 ++- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/closure.rs | 11 ++- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/demand.rs | 5 +- src/librustc_typeck/check/dropck.rs | 6 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 35 +++++---- src/librustc_typeck/check/method/suggest.rs | 8 +- src/librustc_typeck/check/mod.rs | 19 +++-- src/librustc_typeck/check/wfcheck.rs | 3 +- src/librustc_typeck/collect.rs | 16 ++-- .../constrained_generic_params.rs | 2 +- .../impl_wf_check/min_specialization.rs | 6 +- src/librustc_typeck/outlives/explicit.rs | 2 +- src/librustc_typeck/outlives/mod.rs | 40 +++++----- src/librustdoc/clean/auto_trait.rs | 4 +- src/librustdoc/clean/mod.rs | 8 +- src/librustdoc/clean/simplify.rs | 2 +- .../clippy_lints/src/future_not_send.rs | 2 +- .../clippy/clippy_lints/src/methods/mod.rs | 6 +- .../src/needless_pass_by_value.rs | 2 +- .../clippy/clippy_lints/src/utils/mod.rs | 2 +- 55 files changed, 345 insertions(+), 245 deletions(-) diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index 67c8265cb1153..23c9eeb21bb8d 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -25,7 +25,7 @@ use rustc_middle::arena::ArenaAllocatable; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, BoundVar, Const, Ty, TyCtxt}; +use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt}; use std::fmt::Debug; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { @@ -534,10 +534,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { match k1.unpack() { GenericArgKind::Lifetime(r1) => ty::PredicateKind::RegionOutlives( ty::Binder::bind(ty::OutlivesPredicate(r1, r2)), - ), + ) + .to_predicate(self.tcx), GenericArgKind::Type(t1) => ty::PredicateKind::TypeOutlives(ty::Binder::bind( ty::OutlivesPredicate(t1, r2), - )), + )) + .to_predicate(self.tcx), GenericArgKind::Const(..) => { // Consts cannot outlive one another, so we don't expect to // ecounter this branch. @@ -666,7 +668,8 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { param_env: self.param_env, predicate: ty::PredicateKind::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate( sup, sub, - ))), + ))) + .to_predicate(self.infcx.tcx), recursion_depth: 0, }); } diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 2a188b2120556..75f288f1cdcd2 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -39,7 +39,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::{Span, DUMMY_SP}; @@ -307,7 +307,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - ty::PredicateKind::WellFormed(b_ty), + ty::PredicateKind::WellFormed(b_ty).to_predicate(self.infcx.tcx), )); } @@ -398,11 +398,15 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { b: &'tcx ty::Const<'tcx>, ) { let predicate = if a_is_expected { - ty::Predicate::ConstEquate(a, b) + ty::PredicateKind::ConstEquate(a, b) } else { - ty::Predicate::ConstEquate(b, a) + ty::PredicateKind::ConstEquate(b, a) }; - self.obligations.push(Obligation::new(self.trace.cause.clone(), self.param_env, predicate)); + self.obligations.push(Obligation::new( + self.trace.cause.clone(), + self.param_env, + predicate.to_predicate(self.tcx()), + )); } } diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index e423137da8f74..fd3b38e9d67b0 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -11,7 +11,7 @@ pub fn explicit_outlives_bounds<'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> impl Iterator> + 'tcx { debug!("explicit_outlives_bounds()"); - param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate { + param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate.kind() { ty::PredicateKind::Projection(..) | ty::PredicateKind::Trait(..) | ty::PredicateKind::Subtype(..) diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 22231488b7b5c..b51af19883fdd 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -6,7 +6,7 @@ use crate::traits::Obligation; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::TyVar; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. @@ -104,7 +104,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { a_is_expected: self.a_is_expected, a, b, - })), + })) + .to_predicate(self.tcx()), )); Ok(a) diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index b9cafc530cd47..3175ad6c5a44e 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -10,40 +10,49 @@ pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>, ) -> ty::Predicate<'tcx> { - match *pred { + match pred.kind() { ty::PredicateKind::Trait(ref data, constness) => { ty::PredicateKind::Trait(tcx.anonymize_late_bound_regions(data), constness) + .to_predicate(tcx) } ty::PredicateKind::RegionOutlives(ref data) => { ty::PredicateKind::RegionOutlives(tcx.anonymize_late_bound_regions(data)) + .to_predicate(tcx) } ty::PredicateKind::TypeOutlives(ref data) => { ty::PredicateKind::TypeOutlives(tcx.anonymize_late_bound_regions(data)) + .to_predicate(tcx) } ty::PredicateKind::Projection(ref data) => { - ty::PredicateKind::Projection(tcx.anonymize_late_bound_regions(data)) + ty::PredicateKind::Projection(tcx.anonymize_late_bound_regions(data)).to_predicate(tcx) } - ty::PredicateKind::WellFormed(data) => ty::PredicateKind::WellFormed(data), + ty::PredicateKind::WellFormed(data) => { + ty::PredicateKind::WellFormed(data).to_predicate(tcx) + } - ty::PredicateKind::ObjectSafe(data) => ty::PredicateKind::ObjectSafe(data), + ty::PredicateKind::ObjectSafe(data) => { + ty::PredicateKind::ObjectSafe(data).to_predicate(tcx) + } ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) + ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind).to_predicate(tcx) } ty::PredicateKind::Subtype(ref data) => { - ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data)) + ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data)).to_predicate(tcx) } ty::PredicateKind::ConstEvaluatable(def_id, substs) => { - ty::PredicateKind::ConstEvaluatable(def_id, substs) + ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(tcx) } - ty::PredicateKind::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2), + ty::PredicateKind::ConstEquate(c1, c2) => { + ty::PredicateKind::ConstEquate(c1, c2).to_predicate(tcx) + } } } @@ -145,7 +154,7 @@ impl Elaborator<'tcx> { fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) { let tcx = self.visited.tcx; - match obligation.predicate { + match obligation.predicate.kind() { ty::PredicateKind::Trait(ref data, _) => { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); @@ -250,8 +259,9 @@ impl Elaborator<'tcx> { None } }) - .filter(|p| visited.insert(p)) - .map(|p| predicate_obligation(p, None)), + .map(|predicate_kind| predicate_kind.to_predicate(tcx)) + .filter(|predicate| visited.insert(predicate)) + .map(|predicate| predicate_obligation(predicate, None)), ); } } @@ -317,7 +327,7 @@ impl<'tcx, I: Iterator>> Iterator for FilterToT fn next(&mut self) -> Option> { while let Some(obligation) = self.base_iterator.next() { - if let ty::PredicateKind::Trait(data, _) = obligation.predicate { + if let ty::PredicateKind::Trait(data, _) = obligation.predicate.kind() { return Some(data.to_poly_trait_ref()); } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 6e1258e25bbaf..e17e8b7b9640e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1208,7 +1208,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { let def_id = cx.tcx.hir().local_def_id(item.hir_id); let predicates = cx.tcx.predicates_of(def_id); for &(predicate, span) in predicates.predicates { - let predicate_kind_name = match predicate { + let predicate_kind_name = match predicate.kind() { Trait(..) => "Trait", TypeOutlives(..) | RegionOutlives(..) => "Lifetime", @@ -1497,7 +1497,7 @@ impl ExplicitOutlivesRequirements { ) -> Vec> { inferred_outlives .iter() - .filter_map(|(pred, _)| match pred { + .filter_map(|(pred, _)| match pred.kind() { ty::PredicateKind::RegionOutlives(outlives) => { let outlives = outlives.skip_binder(); match outlives.0 { @@ -1516,7 +1516,7 @@ impl ExplicitOutlivesRequirements { ) -> Vec> { inferred_outlives .iter() - .filter_map(|(pred, _)| match pred { + .filter_map(|(pred, _)| match pred.kind() { ty::PredicateKind::TypeOutlives(outlives) => { let outlives = outlives.skip_binder(); outlives.0.is_param(index).then_some(outlives.1) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 19146f68fce80..dea8293431370 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -146,7 +146,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty::Opaque(def, _) => { let mut has_emitted = false; for (predicate, _) in cx.tcx.predicates_of(def).predicates { - if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate { + if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = + predicate.kind() + { let trait_ref = poly_trait_predicate.skip_binder().trait_ref; let def_id = trait_ref.def_id; let descr_pre = diff --git a/src/librustc_middle/ty/codec.rs b/src/librustc_middle/ty/codec.rs index 7ebeb6243be41..68a4ccc3c9e67 100644 --- a/src/librustc_middle/ty/codec.rs +++ b/src/librustc_middle/ty/codec.rs @@ -10,7 +10,7 @@ use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use crate::mir::{self, interpret::Allocation}; use crate::ty::subst::SubstsRef; -use crate::ty::{self, List, Ty, TyCtxt}; +use crate::ty::{self, List, ToPredicate, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; @@ -196,7 +196,7 @@ where (0..decoder.read_usize()?) .map(|_| { // Handle shorthands first, if we have an usize > 0x80. - let predicate = if decoder.positioned_at_shorthand() { + let predicate_kind = if decoder.positioned_at_shorthand() { let pos = decoder.read_usize()?; assert!(pos >= SHORTHAND_OFFSET); let shorthand = pos - SHORTHAND_OFFSET; @@ -205,6 +205,7 @@ where } else { ty::PredicateKind::decode(decoder) }?; + let predicate = predicate_kind.to_predicate(tcx); Ok((predicate, Decodable::decode(decoder)?)) }) .collect::, _>>()?, diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index c005455a3aab6..4a9175d8c1838 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -29,7 +29,9 @@ use crate::ty::{self, DefIdTree, Ty, TypeAndMut}; use crate::ty::{AdtDef, AdtKind, Const, Region}; use crate::ty::{BindingMode, BoundVar}; use crate::ty::{ConstVid, FloatVar, FloatVid, IntVar, IntVid, TyVar, TyVid}; -use crate::ty::{ExistentialPredicate, InferTy, ParamTy, PolyFnSig, Predicate, ProjectionTy}; +use crate::ty::{ + ExistentialPredicate, InferTy, ParamTy, PolyFnSig, Predicate, PredicateKind, ProjectionTy, +}; use crate::ty::{InferConst, ParamConst}; use crate::ty::{List, TyKind, TyS}; use rustc_ast::ast; @@ -2103,6 +2105,11 @@ impl<'tcx> TyCtxt<'tcx> { self.interners.intern_ty(st) } + #[inline] + pub fn mk_predicate(&self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> { + Predicate { kind } + } + pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> { match tm { ast::IntTy::Isize => self.types.isize, diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 16a44328b82fa..3c4c4574bfd54 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1016,7 +1016,17 @@ impl<'tcx> GenericPredicates<'tcx> { } } -pub type Predicate<'tcx> = PredicateKind<'tcx>; +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Lift)] +#[derive(HashStable, TypeFoldable)] +pub struct Predicate<'tcx> { + kind: PredicateKind<'tcx>, +} + +impl Predicate<'tcx> { + pub fn kind(&self) -> PredicateKind<'tcx> { + self.kind + } +} #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] #[derive(HashStable, TypeFoldable)] @@ -1081,7 +1091,7 @@ impl<'tcx> AsRef> for Predicate<'tcx> { } } -impl<'tcx> PredicateKind<'tcx> { +impl<'tcx> Predicate<'tcx> { /// Performs a substitution suitable for going from a /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal @@ -1153,7 +1163,7 @@ impl<'tcx> PredicateKind<'tcx> { // this trick achieves that). let substs = &trait_ref.skip_binder().substs; - match *self { + match self.kind() { PredicateKind::Trait(ref binder, constness) => { PredicateKind::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) } @@ -1181,6 +1191,7 @@ impl<'tcx> PredicateKind<'tcx> { PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) } } + .to_predicate(tcx) } } @@ -1298,57 +1309,67 @@ pub trait ToPredicate<'tcx> { fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; } +impl ToPredicate<'tcx> for PredicateKind<'tcx> { + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + tcx.mk_predicate(*self) + } +} + impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { - fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { ty::PredicateKind::Trait( ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value }), self.constness, ) + .to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { - fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { ty::PredicateKind::Trait( ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }), self.constness, ) + .to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { - fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness) + .to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> { - fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { ty::PredicateKind::Trait(self.value.to_poly_trait_predicate(), self.constness) + .to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { - fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::RegionOutlives(*self) + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + PredicateKind::RegionOutlives(*self).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { - fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::TypeOutlives(*self) + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + PredicateKind::TypeOutlives(*self).to_predicate(tcx) } } impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_predicate(&self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Projection(*self) + fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + PredicateKind::Projection(*self).to_predicate(tcx) } } -impl<'tcx> PredicateKind<'tcx> { +impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_ref(&self) -> Option> { - match *self { + match self.kind() { PredicateKind::Trait(ref t, _) => Some(t.to_poly_trait_ref()), PredicateKind::Projection(..) | PredicateKind::Subtype(..) @@ -1363,7 +1384,7 @@ impl<'tcx> PredicateKind<'tcx> { } pub fn to_opt_type_outlives(&self) -> Option> { - match *self { + match self.kind() { PredicateKind::TypeOutlives(data) => Some(data), PredicateKind::Trait(..) | PredicateKind::Projection(..) diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index c224c937b07fe..786fe55519e7b 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2031,7 +2031,7 @@ define_print_and_forward_display! { } ty::Predicate<'tcx> { - match *self { + match self.kind() { ty::PredicateKind::Trait(ref data, constness) => { if let hir::Constness::Const = constness { p!(write("const ")); @@ -2058,7 +2058,7 @@ define_print_and_forward_display! { print_value_path(def_id, substs), write("` can be evaluated")) } - ty::Predicate::ConstEquate(c1, c2) => { + ty::PredicateKind::ConstEquate(c1, c2) => { p!(write("the constant `"), print(c1), write("` equals `"), diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index 54f34a3e07815..ca7cf97f4af34 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -219,6 +219,12 @@ impl fmt::Debug for ty::ProjectionPredicate<'tcx> { } } +impl fmt::Debug for ty::Predicate<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind()) + } +} + impl fmt::Debug for ty::PredicateKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -242,7 +248,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::ConstEvaluatable(def_id, substs) => { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } - ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), + ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), } } } @@ -469,8 +475,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { - type Lifted = ty::Predicate<'tcx>; +impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { + type Lifted = ty::PredicateKind<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { match *self { ty::PredicateKind::Trait(ref binder, constness) => { @@ -500,8 +506,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::PredicateKind::ConstEvaluatable(def_id, substs) => { tcx.lift(&substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs)) } - ty::Predicate::ConstEquate(c1, c2) => { - tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::Predicate::ConstEquate(c1, c2)) + ty::PredicateKind::ConstEquate(c1, c2) => { + tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) } } } diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 1e4aaa6054525..0c9eef8093f33 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -616,6 +616,7 @@ impl<'tcx> Binder> { } ExistentialPredicate::Projection(p) => { ty::PredicateKind::Projection(Binder(p.with_self_ty(tcx, self_ty))) + .to_predicate(tcx) } ExistentialPredicate::AutoTrait(did) => { let trait_ref = diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index d7ea88725ed1b..ebc8021a3c577 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -576,7 +576,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut found = false; for predicate in bounds.predicates { - if let ty::PredicateKind::TypeOutlives(binder) = predicate { + if let ty::PredicateKind::TypeOutlives(binder) = predicate.kind() { if let ty::OutlivesPredicate(_, ty::RegionKind::ReStatic) = binder.skip_binder() { diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index d3b1b92bdcd10..bdbce1de745ad 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -27,8 +27,8 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts}; use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPolyTraitRef, Ty, - TyCtxt, UserType, UserTypeAnnotationIndex, + self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPolyTraitRef, + ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, }; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; @@ -1016,7 +1016,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.prove_predicate( - ty::PredicateKind::WellFormed(inferred_ty), + ty::PredicateKind::WellFormed(inferred_ty).to_predicate(self.tcx()), Locations::All(span), ConstraintCategory::TypeAnnotation, ); @@ -1268,7 +1268,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { obligations.obligations.push(traits::Obligation::new( ObligationCause::dummy(), param_env, - ty::PredicateKind::WellFormed(revealed_ty), + ty::PredicateKind::WellFormed(revealed_ty).to_predicate(infcx.tcx), )); obligations.add( infcx @@ -2028,7 +2028,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ), }), hir::Constness::NotConst, - ), + ) + .to_predicate(self.tcx()), ), &traits::SelectionError::Unimplemented, false, @@ -2708,11 +2709,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn prove_predicates( &mut self, - predicates: impl IntoIterator>, + predicates: impl IntoIterator>, locations: Locations, category: ConstraintCategory, ) { for predicate in predicates { + let predicate = predicate.to_predicate(self.tcx()); debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,); self.prove_predicate(predicate, locations, category); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 7fdf9133dd4b9..55be4f55a569c 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -23,7 +23,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - loop { let predicates = tcx.predicates_of(current); for (predicate, _) in predicates.predicates { - match predicate { + match predicate.kind() { ty::PredicateKind::RegionOutlives(_) | ty::PredicateKind::TypeOutlives(_) | ty::PredicateKind::WellFormed(_) @@ -46,7 +46,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - match pred.skip_binder().self_ty().kind { ty::Param(ref p) => { // Allow `T: ?const Trait` - if *constness == hir::Constness::NotConst + if constness == hir::Constness::NotConst && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out) { continue; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 64a2a9055f323..9a63e39f535c1 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -90,7 +90,7 @@ where fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool { let ty::GenericPredicates { parent: _, predicates } = predicates; for (predicate, _span) in predicates { - match predicate { + match predicate.kind() { ty::PredicateKind::Trait(poly_predicate, _) => { let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder(); if self.visit_trait(trait_ref) { diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 472f93201c382..2544e4ddea2ec 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1168,7 +1168,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { debug!("instantiate_opaque_types: ty_var={:?}", ty_var); for predicate in &bounds.predicates { - if let ty::PredicateKind::Projection(projection) = &predicate { + if let ty::PredicateKind::Projection(projection) = predicate.kind() { if projection.skip_binder().ty.references_error() { // No point on adding these obligations since there's a type error involved. return ty_var; @@ -1269,7 +1269,7 @@ crate fn required_region_bounds( traits::elaborate_predicates(tcx, predicates) .filter_map(|obligation| { debug!("required_region_bounds(obligation={:?})", obligation); - match obligation.predicate { + match obligation.predicate.kind() { ty::PredicateKind::Projection(..) | ty::PredicateKind::Trait(..) | ty::PredicateKind::Subtype(..) diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index af9623c49981d..bea4725226753 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -341,7 +341,8 @@ impl AutoTraitFinder<'tcx> { already_visited.remove(&pred); self.add_user_pred( &mut user_computed_preds, - ty::PredicateKind::Trait(pred, hir::Constness::NotConst), + ty::PredicateKind::Trait(pred, hir::Constness::NotConst) + .to_predicate(self.tcx), ); predicates.push_back(pred); } else { @@ -412,9 +413,9 @@ impl AutoTraitFinder<'tcx> { let mut should_add_new = true; user_computed_preds.retain(|&old_pred| { if let ( - &ty::PredicateKind::Trait(new_trait, _), + ty::PredicateKind::Trait(new_trait, _), ty::PredicateKind::Trait(old_trait, _), - ) = (&new_pred, old_pred) + ) = (new_pred.kind(), old_pred.kind()) { if new_trait.def_id() == old_trait.def_id() { let new_substs = new_trait.skip_binder().trait_ref.substs; @@ -632,8 +633,8 @@ impl AutoTraitFinder<'tcx> { // // We check this by calling is_of_param on the relevant types // from the various possible predicates - match &predicate { - &ty::PredicateKind::Trait(p, _) => { + match predicate.kind() { + ty::PredicateKind::Trait(p, _) => { if self.is_param_no_infer(p.skip_binder().trait_ref.substs) && !only_projections && is_new_pred @@ -642,7 +643,7 @@ impl AutoTraitFinder<'tcx> { } predicates.push_back(p); } - &ty::PredicateKind::Projection(p) => { + ty::PredicateKind::Projection(p) => { debug!( "evaluate_nested_obligations: examining projection predicate {:?}", predicate @@ -767,12 +768,12 @@ impl AutoTraitFinder<'tcx> { } } } - &ty::PredicateKind::RegionOutlives(ref binder) => { + ty::PredicateKind::RegionOutlives(ref binder) => { if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { return false; } } - &ty::PredicateKind::TypeOutlives(ref binder) => { + ty::PredicateKind::TypeOutlives(ref binder) => { match ( binder.no_bound_vars(), binder.map_bound_ref(|pred| pred.0).no_bound_vars(), diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f997fbadd89fc..f85735064c838 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -252,7 +252,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .emit(); return; } - match obligation.predicate { + match obligation.predicate.kind() { ty::PredicateKind::Trait(ref trait_predicate, _) => { let trait_predicate = self.resolve_vars_if_possible(trait_predicate); @@ -471,7 +471,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { predicate: ty::PredicateKind::Trait( predicate, hir::Constness::NotConst, - ), + ) + .to_predicate(self.tcx), ..obligation.clone() }; if self.predicate_may_hold(&unit_obligation) { @@ -616,7 +617,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) } - ty::Predicate::ConstEquate(..) => { + ty::PredicateKind::ConstEquate(..) => { // Errors for `ConstEquate` predicates show up as // `SelectionError::ConstEvalFailure`, // not `Unimplemented`. @@ -1046,10 +1047,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return true; } - let (cond, error) = match (cond, error) { - (&ty::PredicateKind::Trait(..), &ty::PredicateKind::Trait(ref error, _)) => { - (cond, error) - } + let (cond, error) = match (cond.kind(), error.kind()) { + (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error, _)) => (cond, error), _ => { // FIXME: make this work in other cases too. return false; @@ -1057,7 +1056,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { }; for obligation in super::elaborate_predicates(self.tcx, std::iter::once(*cond)) { - if let ty::PredicateKind::Trait(implication, _) = obligation.predicate { + if let ty::PredicateKind::Trait(implication, _) = obligation.predicate.kind() { let error = error.to_poly_trait_ref(); let implication = implication.to_poly_trait_ref(); // FIXME: I'm just not taking associated types at all here. @@ -1137,7 +1136,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // // this can fail if the problem was higher-ranked, in which // cause I have no idea for a good error message. - if let ty::PredicateKind::Projection(ref data) = predicate { + if let ty::PredicateKind::Projection(ref data) = predicate.kind() { let mut selcx = SelectionContext::new(self); let (data, _) = self.replace_bound_vars_with_fresh_vars( obligation.cause.span, @@ -1417,7 +1416,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - let mut err = match predicate { + let mut err = match predicate.kind() { ty::PredicateKind::Trait(ref data, _) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); @@ -1662,7 +1661,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { if let ( ty::PredicateKind::Trait(pred, _), ObligationCauseCode::BindingObligation(item_def_id, span), - ) = (&obligation.predicate, &obligation.cause.code) + ) = (obligation.predicate.kind(), &obligation.cause.code) { if let (Some(generics), true) = ( self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()), diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index cbc93278353be..6167412642eab 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1242,7 +1242,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // the type. The last generator (`outer_generator` below) has information about where the // bound was introduced. At least one generator should be present for this diagnostic to be // modified. - let (mut trait_ref, mut target_ty) = match obligation.predicate { + let (mut trait_ref, mut target_ty) = match obligation.predicate.kind() { ty::PredicateKind::Trait(p, _) => { (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())) } diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 0497dec4029d1..88ff97e793af4 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -322,7 +322,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { let infcx = self.selcx.infcx(); - match obligation.predicate { + match obligation.predicate.kind() { ty::PredicateKind::Trait(ref data, _) => { let trait_obligation = obligation.with(*data); @@ -523,7 +523,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::Predicate::ConstEquate(c1, c2) => { + ty::PredicateKind::ConstEquate(c1, c2) => { debug!("equating consts: c1={:?} c2={:?}", c1, c2); let stalled_on = &mut pending_obligation.stalled_on; diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index f67669769a10d..3daa9109aafe8 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -333,7 +333,7 @@ pub fn normalize_param_env_or_error<'tcx>( // This works fairly well because trait matching does not actually care about param-env // TypeOutlives predicates - these are normally used by regionck. let outlives_predicates: Vec<_> = predicates - .drain_filter(|predicate| match predicate { + .drain_filter(|predicate| match predicate.kind() { ty::PredicateKind::TypeOutlives(..) => true, _ => false, }) diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 4839a25d85fc9..b2d684e674f02 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -245,7 +245,7 @@ fn predicates_reference_self( .iter() .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) .filter_map(|(predicate, &sp)| { - match predicate { + match predicate.kind() { ty::PredicateKind::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. if data.skip_binder().trait_ref.substs[1..].iter().any(has_self_ty) { @@ -304,19 +304,22 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Search for a predicate like `Self : Sized` amongst the trait bounds. let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; - elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| match obligation.predicate { - ty::PredicateKind::Trait(ref trait_pred, _) => { - trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0) + elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| { + match obligation.predicate.kind() { + ty::PredicateKind::Trait(ref trait_pred, _) => { + trait_pred.def_id() == sized_def_id + && trait_pred.skip_binder().self_ty().is_param(0) + } + ty::PredicateKind::Projection(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::TypeOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => false, } - ty::PredicateKind::Projection(..) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::RegionOutlives(..) - | ty::PredicateKind::WellFormed(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::TypeOutlives(..) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => false, }) } diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 79b6ac3f7ad09..bcf28cb29cb85 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -661,7 +661,7 @@ fn prune_cache_value_obligations<'a, 'tcx>( let mut obligations: Vec<_> = result .obligations .iter() - .filter(|obligation| match obligation.predicate { + .filter(|obligation| match obligation.predicate.kind() { // We found a `T: Foo` predicate, let's check // if `U` references any unresolved type // variables. In principle, we only care if this @@ -930,7 +930,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( let infcx = selcx.infcx(); for predicate in env_predicates { debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); - if let ty::PredicateKind::Projection(data) = predicate { + if let ty::PredicateKind::Projection(data) = predicate.kind() { let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; let is_match = same_def_id @@ -1166,7 +1166,7 @@ fn confirm_object_candidate<'cx, 'tcx>( // select only those projections that are actually projecting an // item with the correct name - let env_predicates = env_predicates.filter_map(|o| match o.predicate { + let env_predicates = env_predicates.filter_map(|o| match o.predicate.kind() { ty::PredicateKind::Projection(data) => { if data.projection_def_id() == obligation.predicate.item_def_id { Some(data) diff --git a/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs index c0470084072a9..5c8719da14e6f 100644 --- a/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs +++ b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs @@ -15,7 +15,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // `&T`, accounts for about 60% percentage of the predicates // we have to prove. No need to canonicalize and all that for // such cases. - if let ty::PredicateKind::Trait(trait_ref, _) = key.value.predicate { + if let ty::PredicateKind::Trait(trait_ref, _) = key.value.predicate.kind() { if let Some(sized_def_id) = tcx.lang_items().sized_trait() { if trait_ref.def_id() == sized_def_id { if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) { diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 2aae0f2703152..59d85281d633b 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -413,7 +413,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - match obligation.predicate { + match obligation.predicate.kind() { ty::PredicateKind::Trait(ref t, _) => { debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(*t); @@ -510,7 +510,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::Predicate::ConstEquate(c1, c2) => { + ty::PredicateKind::ConstEquate(c1, c2) => { debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2); let evaluate = |c: &'tcx ty::Const<'tcx>| { @@ -675,8 +675,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // trait refs. This is important because it's only a cycle // if the regions match exactly. let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); + let tcx = self.tcx(); let cycle = cycle.map(|stack| { ty::PredicateKind::Trait(stack.obligation.predicate, hir::Constness::NotConst) + .to_predicate(tcx) }); if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); @@ -791,7 +793,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { - let result = match predicate { + let result = match predicate.kind() { ty::PredicateKind::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), _ => false, }; @@ -2921,7 +2923,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.push(Obligation::new( obligation.cause.clone(), obligation.param_env, - ty::PredicateKind::ClosureKind(closure_def_id, substs, kind), + ty::PredicateKind::ClosureKind(closure_def_id, substs, kind) + .to_predicate(self.tcx()), )); } diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index a6f4819277c20..1d89ba4efe0ac 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -72,7 +72,7 @@ pub fn predicate_obligations<'a, 'tcx>( let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; // (*) ok to skip binders, because wf code is prepared for it - match *predicate { + match predicate.kind() { ty::PredicateKind::Trait(ref t, _) => { wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) } @@ -102,7 +102,7 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(ty); } } - ty::Predicate::ConstEquate(c1, c2) => { + ty::PredicateKind::ConstEquate(c1, c2) => { wf.compute(c1.ty); wf.compute(c2.ty); } @@ -170,7 +170,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span, _ => impl_item_ref.span, }; - match pred { + match pred.kind() { ty::PredicateKind::Projection(proj) => { // The obligation comes not from the current `impl` nor the `trait` being // implemented, but rather from a "second order" obligation, like in @@ -216,6 +216,10 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( } impl<'a, 'tcx> WfPredicates<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { traits::ObligationCause::new(self.span, self.body_id, code) } @@ -275,9 +279,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.extend(obligations); } + let tcx = self.tcx(); self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map( |ty| { - traits::Obligation::new(cause.clone(), param_env, ty::PredicateKind::WellFormed(ty)) + traits::Obligation::new( + cause.clone(), + param_env, + ty::PredicateKind::WellFormed(ty).to_predicate(tcx), + ) }, )); } @@ -307,7 +316,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs); + let predicate = + ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); } @@ -415,7 +425,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { param_env, ty::PredicateKind::TypeOutlives(ty::Binder::dummy( ty::OutlivesPredicate(rty, r), - )), + )) + .to_predicate(self.tcx()), )); } } @@ -495,16 +506,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // obligations that don't refer to Self and // checking those - let defer_to_coercion = self.infcx.tcx.features().object_safe_for_dispatch; + let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; if !defer_to_coercion { let cause = self.cause(traits::MiscObligation); let component_traits = data.auto_traits().chain(data.principal_def_id()); + let tcx = self.tcx(); self.out.extend(component_traits.map(|did| { traits::Obligation::new( cause.clone(), param_env, - ty::PredicateKind::ObjectSafe(did), + ty::PredicateKind::ObjectSafe(did).to_predicate(tcx), ) })); } @@ -530,7 +542,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, param_env, - ty::PredicateKind::WellFormed(ty), + ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx()), )); } else { // Yes, resolved, proceed with the result. diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index 184b9a9dc1040..7d48b45753810 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -38,8 +38,7 @@ use rustc_middle::traits::{ use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; use rustc_middle::ty::{ - self, Binder, BoundRegion, Predicate, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable, - TypeVisitor, + self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable, TypeVisitor, }; use rustc_span::def_id::DefId; @@ -78,8 +77,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment chalk_ir::InEnvironment>> { let clauses = self.environment.into_iter().filter_map(|clause| match clause { ChalkEnvironmentClause::Predicate(predicate) => { - match predicate { - ty::Predicate::Trait(predicate, _) => { + match &predicate.kind() { + ty::PredicateKind::Trait(predicate, _) => { let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, predicate); @@ -100,9 +99,9 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment None, - ty::Predicate::TypeOutlives(_) => None, - ty::Predicate::Projection(predicate) => { + ty::PredicateKind::RegionOutlives(_) => None, + ty::PredicateKind::TypeOutlives(_) => None, + ty::PredicateKind::Projection(predicate) => { let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, predicate); @@ -122,12 +121,14 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment bug!("unexpected predicate {}", predicate), + ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => { + bug!("unexpected predicate {}", predicate) + } } } ChalkEnvironmentClause::TypeFromEnv(ty) => Some( @@ -154,17 +155,17 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predicate<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - match self { - Predicate::Trait(predicate, _) => predicate.lower_into(interner), + match self.kind() { + ty::PredicateKind::Trait(predicate, _) => predicate.lower_into(interner), // FIXME(chalk): we need to register constraints. - Predicate::RegionOutlives(_predicate) => { + ty::PredicateKind::RegionOutlives(_predicate) => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } - Predicate::TypeOutlives(_predicate) => { + ty::PredicateKind::TypeOutlives(_predicate) => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } - Predicate::Projection(predicate) => predicate.lower_into(interner), - Predicate::WellFormed(ty) => match ty.kind { + ty::PredicateKind::Projection(predicate) => predicate.lower_into(interner), + ty::PredicateKind::WellFormed(ty) => match ty.kind { // These types are always WF. ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) @@ -188,11 +189,13 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi // // We can defer this, but ultimately we'll want to express // some of these in terms of chalk operations. - Predicate::ObjectSafe(..) - | Predicate::ClosureKind(..) - | Predicate::Subtype(..) - | Predicate::ConstEvaluatable(..) - | Predicate::ConstEquate(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), + ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => { + chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + } } } } @@ -439,8 +442,8 @@ impl<'tcx> LowerInto<'tcx, Option, ) -> Option>> { - match &self { - Predicate::Trait(predicate, _) => { + match &self.kind() { + ty::PredicateKind::Trait(predicate, _) => { let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, predicate); @@ -449,16 +452,16 @@ impl<'tcx> LowerInto<'tcx, Option None, - Predicate::TypeOutlives(_predicate) => None, - Predicate::Projection(_predicate) => None, - Predicate::WellFormed(_ty) => None, - - Predicate::ObjectSafe(..) - | Predicate::ClosureKind(..) - | Predicate::Subtype(..) - | Predicate::ConstEvaluatable(..) - | Predicate::ConstEquate(..) => bug!("unexpected predicate {}", &self), + ty::PredicateKind::RegionOutlives(_predicate) => None, + ty::PredicateKind::TypeOutlives(_predicate) => None, + ty::PredicateKind::Projection(_predicate) => None, + ty::PredicateKind::WellFormed(_ty) => None, + + ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", &self), } } } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index aed5729b34a2c..5dee71a2338cc 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -94,7 +94,7 @@ fn compute_implied_outlives_bounds<'tcx>( // region relationships. implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { assert!(!obligation.has_escaping_bound_vars()); - match obligation.predicate { + match obligation.predicate.kind() { ty::PredicateKind::Trait(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Projection(..) diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index 11604cc31870f..fcb75142269df 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -40,7 +40,7 @@ fn normalize_generic_arg_after_erasing_regions<'tcx>( } fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { - match p { + match p.kind() { ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, ty::PredicateKind::Trait(..) | ty::PredicateKind::Projection(..) diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 58fa927c021e0..2a338383c9a07 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -7,8 +7,8 @@ use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; use rustc_middle::ty::{ - self, FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, - Variance, + self, FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, ToPredicate, Ty, TyCtxt, + TypeFoldable, Variance, }; use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -141,7 +141,9 @@ impl AscribeUserTypeCx<'me, 'tcx> { self.relate(self_ty, Variance::Invariant, impl_self_ty)?; - self.prove_predicate(ty::PredicateKind::WellFormed(impl_self_ty)); + self.prove_predicate( + ty::PredicateKind::WellFormed(impl_self_ty).to_predicate(self.tcx()), + ); } // In addition to proving the predicates, we have to @@ -155,7 +157,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { // them? This would only be relevant if some input // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... - self.prove_predicate(ty::PredicateKind::WellFormed(ty)); + self.prove_predicate(ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx())); Ok(()) } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f8144d4aade4e..3526a1b59f384 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1596,7 +1596,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", obligation.predicate ); - match obligation.predicate { + match obligation.predicate.kind() { ty::PredicateKind::Trait(pred, _) => { associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 6ade48b80c8a5..f393121a0adb8 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -12,7 +12,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, GenericParamDefKind, Ty}; +use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty}; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::ArgKind; @@ -206,7 +206,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligation.predicate ); - if let ty::PredicateKind::Projection(ref proj_predicate) = obligation.predicate { + if let ty::PredicateKind::Projection(ref proj_predicate) = + obligation.predicate.kind() + { // Given a Projection predicate, we can potentially infer // the complete signature. self.deduce_sig_from_projection(Some(obligation.cause.span), proj_predicate) @@ -529,7 +531,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( supplied_ty, closure_body_region, - ))), + ))) + .to_predicate(self.tcx), )); } @@ -641,7 +644,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // where R is the return type we are expecting. This type `T` // will be our output. let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| { - if let ty::PredicateKind::Projection(ref proj_predicate) = obligation.predicate { + if let ty::PredicateKind::Projection(ref proj_predicate) = obligation.predicate.kind() { self.deduce_future_output_from_projection(obligation.cause.span, proj_predicate) } else { None diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8a93b05ac8db0..705bace4a9ccc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -596,7 +596,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { while !queue.is_empty() { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); - let trait_pred = match obligation.predicate { + let trait_pred = match obligation.predicate.kind() { ty::PredicateKind::Trait(trait_pred, _) if traits.contains(&trait_pred.def_id()) => { diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 550a236279550..fc7a9c1d59b76 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::lang_items::{CloneTraitLangItem, DerefTraitLangItem}; use rustc_hir::{is_range_literal, Node}; use rustc_middle::ty::adjustment::AllowTwoPhase; -use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut}; +use rustc_middle::ty::{self, AssocItem, ToPredicate, Ty, TypeAndMut}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -654,7 +654,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, // `U` ty: expected, - })); + })) + .to_predicate(self.tcx); let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); let impls_deref = self.infcx.predicate_may_hold(&obligation); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 51d28f7c57c65..3843b97f23d41 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -230,12 +230,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // could be extended easily also to the other `Predicate`. let predicate_matches_closure = |p: &'_ Predicate<'tcx>| { let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); - match (predicate, p) { + match (predicate.kind(), p.kind()) { (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => { - relator.relate(a, b).is_ok() + relator.relate(&a, &b).is_ok() } (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => { - relator.relate(a, b).is_ok() + relator.relate(&a, &b).is_ok() } _ => predicate == p, } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 64917bf4c9f44..410c5efdf37d4 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -574,7 +574,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { }; traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied()) - .filter_map(|obligation| match obligation.predicate { + .filter_map(|obligation| match obligation.predicate.kind() { ty::PredicateKind::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => { let span = predicates .predicates diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index d1da0bbda540a..aae02ea0273f9 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(method_ty), + ty::PredicateKind::WellFormed(method_ty).to_predicate(tcx), )); let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index f1a1c48da166a..91562d576ea80 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -796,23 +796,26 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { // FIXME: do we want to commit to this behavior for param bounds? - let bounds = self.param_env.caller_bounds.iter().filter_map(|predicate| match *predicate { - ty::PredicateKind::Trait(ref trait_predicate, _) => { - match trait_predicate.skip_binder().trait_ref.self_ty().kind { - ty::Param(ref p) if *p == param_ty => Some(trait_predicate.to_poly_trait_ref()), - _ => None, + let bounds = + self.param_env.caller_bounds.iter().filter_map(|predicate| match predicate.kind() { + ty::PredicateKind::Trait(ref trait_predicate, _) => { + match trait_predicate.skip_binder().trait_ref.self_ty().kind { + ty::Param(ref p) if *p == param_ty => { + Some(trait_predicate.to_poly_trait_ref()) + } + _ => None, + } } - } - ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Projection(..) - | ty::PredicateKind::RegionOutlives(..) - | ty::PredicateKind::WellFormed(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::TypeOutlives(..) - | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, - }); + ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Projection(..) + | ty::PredicateKind::RegionOutlives(..) + | ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::TypeOutlives(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::ConstEquate(..) => None, + }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { let trait_ref = this.erase_late_bound_regions(&poly_trait_ref); diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 321cc7a3c4bf5..7ca3eb884d88f 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -575,7 +575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut collect_type_param_suggestions = |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| { if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) = - (&self_ty.kind, parent_pred) + (&self_ty.kind, parent_pred.kind()) { if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind { let node = def.did.as_local().map(|def_id| { @@ -626,8 +626,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } }; - let mut format_pred = |pred| { - match pred { + let mut format_pred = |pred: ty::Predicate<'tcx>| { + match pred.kind() { ty::PredicateKind::Projection(pred) => { // `::Item = String`. let trait_ref = @@ -946,7 +946,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - unsatisfied_predicates.iter().all(|(p, _)| match p { + unsatisfied_predicates.iter().all(|(p, _)| match p.kind() { // Hide traits if they are present in predicates as they can be fixed without // having to implement them. ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b9055722bb571..c452859414cfb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2223,7 +2223,7 @@ fn bounds_from_generic_predicates( let mut projections = vec![]; for (predicate, _) in predicates.predicates { debug!("predicate {:?}", predicate); - match predicate { + match predicate.kind() { ty::PredicateKind::Trait(trait_predicate, _) => { let entry = types.entry(trait_predicate.skip_binder().self_ty()).or_default(); let def_id = trait_predicate.skip_binder().def_id(); @@ -2769,7 +2769,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { ty::GenericPredicates { parent: None, predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map( - |&predicate| match predicate { + |&predicate| match predicate.kind() { ty::PredicateKind::Trait(ref data, _) if data.skip_binder().self_ty().is_param(index) => { @@ -3379,7 +3379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::ConstEvaluatable(def_id, substs), + ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx), )); } @@ -3428,7 +3428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(ty), + ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx), )); } @@ -3857,7 +3857,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow() .pending_obligations() .into_iter() - .filter_map(move |obligation| match obligation.predicate { + .filter_map(move |obligation| match obligation.predicate.kind() { ty::PredicateKind::Projection(ref data) => { Some((data.to_poly_trait_ref(self.tcx), obligation)) } @@ -4208,7 +4208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - if let ty::PredicateKind::Trait(predicate, _) = error.obligation.predicate { + if let ty::PredicateKind::Trait(predicate, _) = error.obligation.predicate.kind() { // Collect the argument position for all arguments that could have caused this // `FulfillmentError`. let mut referenced_in = final_arg_types @@ -4255,7 +4255,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::ExprKind::Path(qpath) = &path.kind { if let hir::QPath::Resolved(_, path) = &qpath { for error in errors { - if let ty::PredicateKind::Trait(predicate, _) = error.obligation.predicate { + if let ty::PredicateKind::Trait(predicate, _) = + error.obligation.predicate.kind() + { // If any of the type arguments in this path segment caused the // `FullfillmentError`, point at its span (#61860). for arg in path @@ -5327,7 +5329,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::Projection(ty::Binder::bind(ty::ProjectionPredicate { projection_ty, ty: expected, - })); + })) + .to_predicate(self.tcx); let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); debug!("suggest_missing_await: trying obligation {:?}", obligation); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index aa3865059392f..d5db613d9dcad 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -425,7 +425,8 @@ fn check_type_defn<'tcx, F>( fcx.register_predicate(traits::Obligation::new( cause, fcx.param_env, - ty::PredicateKind::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs), + ty::PredicateKind::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs) + .to_predicate(fcx.tcx), )); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 529c9f9f50508..fa4c9edcd218d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -548,7 +548,7 @@ fn type_param_predicates( let extra_predicates = extend.into_iter().chain( icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true)) .into_iter() - .filter(|(predicate, _)| match predicate { + .filter(|(predicate, _)| match predicate.kind() { ty::PredicateKind::Trait(ref data, _) => { data.skip_binder().self_ty().is_param(index) } @@ -996,7 +996,7 @@ fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredi // which will, in turn, reach indirect supertraits. for &(pred, span) in superbounds { debug!("superbound: {:?}", pred); - if let ty::PredicateKind::Trait(bound, _) = pred { + if let ty::PredicateKind::Trait(bound, _) = pred.kind() { tcx.at(span).super_predicates_of(bound.def_id()); } } @@ -1901,7 +1901,8 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let re_root_empty = tcx.lifetimes.re_root_empty; let predicate = ty::OutlivesPredicate(ty, re_root_empty); predicates.push(( - ty::PredicateKind::TypeOutlives(ty::Binder::dummy(predicate)), + ty::PredicateKind::TypeOutlives(ty::Binder::dummy(predicate)) + .to_predicate(tcx), span, )); } @@ -1930,7 +1931,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); let pred = ty::Binder::bind(ty::OutlivesPredicate(ty, region)); - predicates.push((ty::PredicateKind::TypeOutlives(pred), lifetime.span)) + predicates.push(( + ty::PredicateKind::TypeOutlives(pred).to_predicate(tcx), + lifetime.span, + )) } } } @@ -1947,7 +1951,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat }; let pred = ty::Binder::bind(ty::OutlivesPredicate(r1, r2)); - (ty::PredicateKind::RegionOutlives(pred), span) + (ty::PredicateKind::RegionOutlives(pred).to_predicate(icx.tcx), span) })) } @@ -2118,7 +2122,7 @@ fn predicates_from_bound<'tcx>( hir::GenericBound::Outlives(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region)); - vec![(ty::PredicateKind::TypeOutlives(pred), lifetime.span)] + vec![(ty::PredicateKind::TypeOutlives(pred).to_predicate(astconv.tcx()), lifetime.span)] } } } diff --git a/src/librustc_typeck/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs index c1be430b93e98..34497d12a4ece 100644 --- a/src/librustc_typeck/constrained_generic_params.rs +++ b/src/librustc_typeck/constrained_generic_params.rs @@ -180,7 +180,7 @@ pub fn setup_constraining_predicates<'tcx>( changed = false; for j in i..predicates.len() { - if let ty::PredicateKind::Projection(ref poly_projection) = predicates[j].0 { + if let ty::PredicateKind::Projection(ref poly_projection) = predicates[j].0.kind() { // Note that we can skip binder here because the impl // trait ref never contains any late-bound regions. let projection = poly_projection.skip_binder(); diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index 89d63107a9c29..d30dc1b7a475e 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -204,7 +204,7 @@ fn unconstrained_parent_impl_substs<'tcx>( // the functions in `cgp` add the constrained parameters to a list of // unconstrained parameters. for (predicate, _) in impl_generic_predicates.predicates.iter() { - if let ty::PredicateKind::Projection(proj) = predicate { + if let ty::PredicateKind::Projection(proj) = predicate.kind() { let projection_ty = proj.skip_binder().projection_ty; let projected_ty = proj.skip_binder().ty; @@ -368,7 +368,7 @@ fn check_predicates<'tcx>( fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: &ty::Predicate<'tcx>, span: Span) { debug!("can_specialize_on(predicate = {:?})", predicate); - match predicate { + match predicate.kind() { // Global predicates are either always true or always false, so we // are fine to specialize on. _ if predicate.is_global() => (), @@ -401,7 +401,7 @@ fn trait_predicate_kind<'tcx>( tcx: TyCtxt<'tcx>, predicate: &ty::Predicate<'tcx>, ) -> Option { - match predicate { + match predicate.kind() { ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => { Some(tcx.trait_def(pred.def_id()).specialization_kind) } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index bc8d25f953820..5740cc224cc57 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -29,7 +29,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { // process predicates and convert to `RequiredPredicates` entry, see below for &(predicate, span) in predicates.predicates { - match predicate { + match predicate.kind() { ty::PredicateKind::TypeOutlives(predicate) => { let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder(); insert_outlives_predicate( diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index d88fda3550500..1b2b08a2e62ee 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -30,7 +30,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec = predicates .iter() - .map(|(out_pred, _)| match out_pred { + .map(|(out_pred, _)| match out_pred.kind() { ty::PredicateKind::RegionOutlives(p) => p.to_string(), ty::PredicateKind::TypeOutlives(p) => p.to_string(), err => bug!("unexpected predicate {:?}", err), @@ -82,22 +82,26 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CratePredica .iter() .map(|(&def_id, set)| { let predicates = &*tcx.arena.alloc_from_iter(set.iter().filter_map( - |(ty::OutlivesPredicate(kind1, region2), &span)| match kind1.unpack() { - GenericArgKind::Type(ty1) => Some(( - ty::PredicateKind::TypeOutlives(ty::Binder::bind(ty::OutlivesPredicate( - ty1, region2, - ))), - span, - )), - GenericArgKind::Lifetime(region1) => Some(( - ty::PredicateKind::RegionOutlives(ty::Binder::bind(ty::OutlivesPredicate( - region1, region2, - ))), - span, - )), - GenericArgKind::Const(_) => { - // Generic consts don't impose any constraints. - None + |(ty::OutlivesPredicate(kind1, region2), &span)| { + match kind1.unpack() { + GenericArgKind::Type(ty1) => Some(( + ty::PredicateKind::TypeOutlives(ty::Binder::bind( + ty::OutlivesPredicate(ty1, region2), + )) + .to_predicate(tcx), + span, + )), + GenericArgKind::Lifetime(region1) => Some(( + ty::PredicateKind::RegionOutlives(ty::Binder::bind( + ty::OutlivesPredicate(region1, region2), + )) + .to_predicate(tcx), + span, + )), + GenericArgKind::Const(_) => { + // Generic consts don't impose any constraints. + None + } } }, )); diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index ff05c4e583269..423160f3a9e01 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -315,7 +315,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, pred: ty::Predicate<'tcx>, ) -> FxHashSet { - let regions = match pred { + let regions = match pred.kind() { ty::PredicateKind::Trait(poly_trait_pred, _) => { tcx.collect_referenced_late_bound_regions(&poly_trait_pred) } @@ -465,7 +465,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .iter() .filter(|p| { !orig_bounds.contains(p) - || match p { + || match p.kind() { ty::PredicateKind::Trait(pred, _) => pred.def_id() == sized_trait, _ => false, } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 002af495ff226..cf1a39232bc78 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -481,7 +481,7 @@ impl Clean for hir::WherePredicate<'_> { impl<'a> Clean> for ty::Predicate<'a> { fn clean(&self, cx: &DocContext<'_>) -> Option { - match *self { + match self.kind() { ty::PredicateKind::Trait(ref pred, _) => Some(pred.clean(cx)), ty::PredicateKind::Subtype(ref pred) => Some(pred.clean(cx)), ty::PredicateKind::RegionOutlives(ref pred) => pred.clean(cx), @@ -763,7 +763,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx if let ty::Param(param) = outlives.skip_binder().0.kind { return Some(param.index); } - } else if let ty::PredicateKind::Projection(p) = p { + } else if let ty::PredicateKind::Projection(p) = p.kind() { if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().kind { projection = Some(p); return Some(param.index); @@ -1661,7 +1661,7 @@ impl<'tcx> Clean for Ty<'tcx> { .filter_map(|predicate| { let trait_ref = if let Some(tr) = predicate.to_opt_poly_trait_ref() { tr - } else if let ty::PredicateKind::TypeOutlives(pred) = *predicate { + } else if let ty::PredicateKind::TypeOutlives(pred) = predicate.kind() { // these should turn up at the end if let Some(r) = pred.skip_binder().1.clean(cx) { regions.push(GenericBound::Outlives(r)); @@ -1682,7 +1682,7 @@ impl<'tcx> Clean for Ty<'tcx> { .predicates .iter() .filter_map(|pred| { - if let ty::PredicateKind::Projection(proj) = *pred { + if let ty::PredicateKind::Projection(proj) = pred.kind() { let proj = proj.skip_binder(); if proj.projection_ty.trait_ref(cx.tcx) == *trait_ref.skip_binder() diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index cc91c50346180..37c613f41224a 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -141,7 +141,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId) .predicates .iter() .filter_map(|(pred, _)| { - if let ty::PredicateKind::Trait(ref pred, _) = *pred { + if let ty::PredicateKind::Trait(ref pred, _) = pred.kind() { if pred.skip_binder().trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 2c2965433fd0e..0a02aa7533c17 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -91,7 +91,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FutureNotSend { cx.tcx.infer_ctxt().enter(|infcx| { for FulfillmentError { obligation, .. } in send_errors { infcx.maybe_note_obligation_cause_for_async_await(db, &obligation); - if let Trait(trait_pred, _) = obligation.predicate { + if let Trait(trait_pred, _) = obligation.predicate.kind() { let trait_ref = trait_pred.to_poly_trait_ref(); db.note(&*format!( "`{}` doesn't implement `{}`", diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 79c21d9bc0a64..810a226b50d2a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -1496,8 +1496,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { if let ty::Opaque(def_id, _) = ret_ty.kind { // one of the associated types must be Self for predicate in cx.tcx.predicates_of(def_id).predicates { - match predicate { - (ty::PredicateKind::Projection(poly_projection_predicate), _) => { + match predicate.0.kind() { + ty::PredicateKind::Projection(poly_projection_predicate) => { let binder = poly_projection_predicate.ty(); let associated_type = binder.skip_binder(); @@ -1506,7 +1506,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { return; } }, - (_, _) => {}, + _ => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 8f94f143bae71..60c5360054334 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter().copied()) .filter(|p| !p.is_global()) .filter_map(|obligation| { - if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate { + if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate.kind() { if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars() { return None; diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 3f5693d7e6809..f22473275c466 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1299,7 +1299,7 @@ pub fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> boo ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.predicates_of(*def_id).predicates { - if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate { + if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate.kind() { if must_use_attr(&cx.tcx.get_attrs(poly_trait_predicate.skip_binder().trait_ref.def_id)).is_some() { return true; } From 57746f943bef5720d97ad2cb413c54b0f432566b Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 22:04:22 +0200 Subject: [PATCH 087/695] intern `PredicateKind` --- src/librustc_infer/traits/mod.rs | 2 +- src/librustc_middle/ty/context.rs | 23 +++++++++++++++---- src/librustc_middle/ty/mod.rs | 6 ++--- src/librustc_middle/ty/structural_impls.rs | 10 ++++++++ .../traits/fulfill.rs | 2 +- src/librustc_traits/type_op.rs | 6 ++--- 6 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 8d95904b355da..892a62855a0a2 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -59,7 +59,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PredicateObligation<'_>, 112); +static_assert_size!(PredicateObligation<'_>, 88); pub type Obligations<'tcx, O> = Vec>; pub type PredicateObligations<'tcx> = Vec>; diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 4a9175d8c1838..7d192a44eaf2a 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -29,10 +29,9 @@ use crate::ty::{self, DefIdTree, Ty, TypeAndMut}; use crate::ty::{AdtDef, AdtKind, Const, Region}; use crate::ty::{BindingMode, BoundVar}; use crate::ty::{ConstVid, FloatVar, FloatVid, IntVar, IntVid, TyVar, TyVid}; -use crate::ty::{ - ExistentialPredicate, InferTy, ParamTy, PolyFnSig, Predicate, PredicateKind, ProjectionTy, -}; +use crate::ty::{ExistentialPredicate, Predicate, PredicateKind}; use crate::ty::{InferConst, ParamConst}; +use crate::ty::{InferTy, ParamTy, PolyFnSig, ProjectionTy}; use crate::ty::{List, TyKind, TyS}; use rustc_ast::ast; use rustc_ast::expand::allocator::AllocatorKind; @@ -91,6 +90,7 @@ pub struct CtxtInterners<'tcx> { canonical_var_infos: InternedSet<'tcx, List>, region: InternedSet<'tcx, RegionKind>, existential_predicates: InternedSet<'tcx, List>>, + predicate_kind: InternedSet<'tcx, PredicateKind<'tcx>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, @@ -109,6 +109,7 @@ impl<'tcx> CtxtInterners<'tcx> { region: Default::default(), existential_predicates: Default::default(), canonical_var_infos: Default::default(), + predicate_kind: Default::default(), predicates: Default::default(), projs: Default::default(), place_elems: Default::default(), @@ -1579,6 +1580,7 @@ macro_rules! nop_list_lift { nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} +nop_lift! {predicate_kind; &'a PredicateKind<'a> => &'tcx PredicateKind<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} @@ -2017,8 +2019,14 @@ impl<'tcx> Borrow<[traits::ChalkEnvironmentClause<'tcx>]> } } +impl<'tcx> Borrow> for Interned<'tcx, PredicateKind<'tcx>> { + fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> { + &self.0 + } +} + macro_rules! direct_interners { - ($($name:ident: $method:ident($ty:ty)),+) => { + ($($name:ident: $method:ident($ty:ty),)+) => { $(impl<'tcx> PartialEq for Interned<'tcx, $ty> { fn eq(&self, other: &Self) -> bool { self.0 == other.0 @@ -2043,7 +2051,11 @@ macro_rules! direct_interners { } } -direct_interners!(region: mk_region(RegionKind), const_: mk_const(Const<'tcx>)); +direct_interners!( + region: mk_region(RegionKind), + const_: mk_const(Const<'tcx>), + predicate_kind: intern_predicate_kind(PredicateKind<'tcx>), +); macro_rules! slice_interners { ($($field:ident: $method:ident($ty:ty)),+) => ( @@ -2107,6 +2119,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_predicate(&self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> { + let kind = self.intern_predicate_kind(kind); Predicate { kind } } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 3c4c4574bfd54..72c785074996b 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1017,14 +1017,14 @@ impl<'tcx> GenericPredicates<'tcx> { } #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Lift)] -#[derive(HashStable, TypeFoldable)] +#[derive(HashStable)] pub struct Predicate<'tcx> { - kind: PredicateKind<'tcx>, + kind: &'tcx PredicateKind<'tcx>, } impl Predicate<'tcx> { pub fn kind(&self) -> PredicateKind<'tcx> { - self.kind + *self.kind } } diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index ca7cf97f4af34..babe0c54801e8 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -987,6 +987,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + folder.tcx().mk_predicate(ty::PredicateKind::super_fold_with(self.kind, folder)) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + ty::PredicateKind::super_visit_with(self.kind, visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { fn super_fold_with>(&self, folder: &mut F) -> Self { fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v)) diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 88ff97e793af4..6f6430c100da9 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -83,7 +83,7 @@ pub struct PendingPredicateObligation<'tcx> { // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PendingPredicateObligation<'_>, 136); +static_assert_size!(PendingPredicateObligation<'_>, 112); impl<'a, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 2a338383c9a07..22077b49c3b77 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -6,10 +6,8 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; -use rustc_middle::ty::{ - self, FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, ToPredicate, Ty, TyCtxt, - TypeFoldable, Variance, -}; +use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance}; +use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate}; use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::infer::InferCtxtExt; From 6544d7b6b1c06b1c5607118365fb992a39075b0c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 16:54:55 +0200 Subject: [PATCH 088/695] change `Predicate::kind` to return a reference --- src/librustc_infer/traits/util.rs | 18 +++++----- src/librustc_middle/ty/mod.rs | 33 ++++++++++--------- src/librustc_middle/ty/print/pretty.rs | 16 ++++----- .../transform/qualify_min_const_fn.rs | 2 +- .../traits/auto_trait.rs | 4 +-- .../traits/error_reporting/mod.rs | 4 +-- .../traits/fulfill.rs | 10 +++--- .../traits/project.rs | 12 +++---- src/librustc_trait_selection/traits/select.rs | 14 ++++---- src/librustc_trait_selection/traits/wf.rs | 12 +++---- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/dropck.rs | 4 +-- 13 files changed, 66 insertions(+), 67 deletions(-) diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 3175ad6c5a44e..88fc1460475df 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -11,42 +11,42 @@ pub fn anonymize_predicate<'tcx>( pred: &ty::Predicate<'tcx>, ) -> ty::Predicate<'tcx> { match pred.kind() { - ty::PredicateKind::Trait(ref data, constness) => { + &ty::PredicateKind::Trait(ref data, constness) => { ty::PredicateKind::Trait(tcx.anonymize_late_bound_regions(data), constness) .to_predicate(tcx) } - ty::PredicateKind::RegionOutlives(ref data) => { + ty::PredicateKind::RegionOutlives(data) => { ty::PredicateKind::RegionOutlives(tcx.anonymize_late_bound_regions(data)) .to_predicate(tcx) } - ty::PredicateKind::TypeOutlives(ref data) => { + ty::PredicateKind::TypeOutlives(data) => { ty::PredicateKind::TypeOutlives(tcx.anonymize_late_bound_regions(data)) .to_predicate(tcx) } - ty::PredicateKind::Projection(ref data) => { + ty::PredicateKind::Projection(data) => { ty::PredicateKind::Projection(tcx.anonymize_late_bound_regions(data)).to_predicate(tcx) } - ty::PredicateKind::WellFormed(data) => { + &ty::PredicateKind::WellFormed(data) => { ty::PredicateKind::WellFormed(data).to_predicate(tcx) } - ty::PredicateKind::ObjectSafe(data) => { + &ty::PredicateKind::ObjectSafe(data) => { ty::PredicateKind::ObjectSafe(data).to_predicate(tcx) } - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { + &ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind).to_predicate(tcx) } - ty::PredicateKind::Subtype(ref data) => { + ty::PredicateKind::Subtype(data) => { ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data)).to_predicate(tcx) } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(tcx) } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 72c785074996b..6bb47a8f30e74 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1023,8 +1023,8 @@ pub struct Predicate<'tcx> { } impl Predicate<'tcx> { - pub fn kind(&self) -> PredicateKind<'tcx> { - *self.kind + pub fn kind(&self) -> &'tcx PredicateKind<'tcx> { + self.kind } } @@ -1163,35 +1163,36 @@ impl<'tcx> Predicate<'tcx> { // this trick achieves that). let substs = &trait_ref.skip_binder().substs; - match self.kind() { - PredicateKind::Trait(ref binder, constness) => { + let predicate = match self.kind() { + &PredicateKind::Trait(ref binder, constness) => { PredicateKind::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) } - PredicateKind::Subtype(ref binder) => { + PredicateKind::Subtype(binder) => { PredicateKind::Subtype(binder.map_bound(|data| data.subst(tcx, substs))) } - PredicateKind::RegionOutlives(ref binder) => { + PredicateKind::RegionOutlives(binder) => { PredicateKind::RegionOutlives(binder.map_bound(|data| data.subst(tcx, substs))) } - PredicateKind::TypeOutlives(ref binder) => { + PredicateKind::TypeOutlives(binder) => { PredicateKind::TypeOutlives(binder.map_bound(|data| data.subst(tcx, substs))) } - PredicateKind::Projection(ref binder) => { + PredicateKind::Projection(binder) => { PredicateKind::Projection(binder.map_bound(|data| data.subst(tcx, substs))) } - PredicateKind::WellFormed(data) => PredicateKind::WellFormed(data.subst(tcx, substs)), - PredicateKind::ObjectSafe(trait_def_id) => PredicateKind::ObjectSafe(trait_def_id), - PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { + &PredicateKind::WellFormed(data) => PredicateKind::WellFormed(data.subst(tcx, substs)), + &PredicateKind::ObjectSafe(trait_def_id) => PredicateKind::ObjectSafe(trait_def_id), + &PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { PredicateKind::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind) } - PredicateKind::ConstEvaluatable(def_id, const_substs) => { + &PredicateKind::ConstEvaluatable(def_id, const_substs) => { PredicateKind::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)) } PredicateKind::ConstEquate(c1, c2) => { PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) } - } - .to_predicate(tcx) + }; + + predicate.to_predicate(tcx) } } @@ -1370,7 +1371,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_ref(&self) -> Option> { match self.kind() { - PredicateKind::Trait(ref t, _) => Some(t.to_poly_trait_ref()), + &PredicateKind::Trait(ref t, _) => Some(t.to_poly_trait_ref()), PredicateKind::Projection(..) | PredicateKind::Subtype(..) | PredicateKind::RegionOutlives(..) @@ -1385,7 +1386,7 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_type_outlives(&self) -> Option> { match self.kind() { - PredicateKind::TypeOutlives(data) => Some(data), + &PredicateKind::TypeOutlives(data) => Some(data), PredicateKind::Trait(..) | PredicateKind::Projection(..) | PredicateKind::Subtype(..) diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 786fe55519e7b..f4b795e548867 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2032,28 +2032,28 @@ define_print_and_forward_display! { ty::Predicate<'tcx> { match self.kind() { - ty::PredicateKind::Trait(ref data, constness) => { + &ty::PredicateKind::Trait(ref data, constness) => { if let hir::Constness::Const = constness { p!(write("const ")); } p!(print(data)) } - ty::PredicateKind::Subtype(ref predicate) => p!(print(predicate)), - ty::PredicateKind::RegionOutlives(ref predicate) => p!(print(predicate)), - ty::PredicateKind::TypeOutlives(ref predicate) => p!(print(predicate)), - ty::PredicateKind::Projection(ref predicate) => p!(print(predicate)), + ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), + ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)), + ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)), + ty::PredicateKind::Projection(predicate) => p!(print(predicate)), ty::PredicateKind::WellFormed(ty) => p!(print(ty), write(" well-formed")), - ty::PredicateKind::ObjectSafe(trait_def_id) => { + &ty::PredicateKind::ObjectSafe(trait_def_id) => { p!(write("the trait `"), print_def_path(trait_def_id, &[]), write("` is object-safe")) } - ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => { + &ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => { p!(write("the closure `"), print_value_path(closure_def_id, &[]), write("` implements the trait `{}`", kind)) } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { p!(write("the constant `"), print_value_path(def_id, substs), write("` can be evaluated")) diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 55be4f55a569c..ead530bded861 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -39,7 +39,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - ty::PredicateKind::Subtype(_) => { bug!("subtype predicate on function: {:#?}", predicate) } - ty::PredicateKind::Trait(pred, constness) => { + &ty::PredicateKind::Trait(pred, constness) => { if Some(pred.def_id()) == tcx.lang_items().sized_trait() { continue; } diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index bea4725226753..716cbce60dcc9 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -634,7 +634,7 @@ impl AutoTraitFinder<'tcx> { // We check this by calling is_of_param on the relevant types // from the various possible predicates match predicate.kind() { - ty::PredicateKind::Trait(p, _) => { + &ty::PredicateKind::Trait(p, _) => { if self.is_param_no_infer(p.skip_binder().trait_ref.substs) && !only_projections && is_new_pred @@ -643,7 +643,7 @@ impl AutoTraitFinder<'tcx> { } predicates.push_back(p); } - ty::PredicateKind::Projection(p) => { + &ty::PredicateKind::Projection(p) => { debug!( "evaluate_nested_obligations: examining projection predicate {:?}", predicate diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f85735064c838..2aef8aaf0e303 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -524,12 +524,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { + &ty::PredicateKind::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); report_object_safety_error(self.tcx, span, trait_def_id, violations) } - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { + &ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { let found_kind = self.closure_kind(closure_substs).unwrap(); let closure_span = self.tcx.sess.source_map().guess_head_span( diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 6f6430c100da9..e44163f7bb1a4 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -443,7 +443,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::ObjectSafe(trait_def_id) => { + &ty::PredicateKind::ObjectSafe(trait_def_id) => { if !self.selcx.tcx().is_object_safe(trait_def_id) { ProcessResult::Error(CodeSelectionError(Unimplemented)) } else { @@ -451,7 +451,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::ClosureKind(_, closure_substs, kind) => { + &ty::PredicateKind::ClosureKind(_, closure_substs, kind) => { match self.selcx.infcx().closure_kind(closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { @@ -464,7 +464,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::WellFormed(ty) => { + &ty::PredicateKind::WellFormed(ty) => { match wf::obligations( self.selcx.infcx(), obligation.param_env, @@ -481,7 +481,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::Subtype(ref subtype) => { + ty::PredicateKind::Subtype(subtype) => { match self.selcx.infcx().subtype_predicate( &obligation.cause, obligation.param_env, @@ -510,7 +510,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { match self.selcx.infcx().const_eval_resolve( obligation.param_env, def_id, diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index bcf28cb29cb85..7b72cf15da4d8 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -930,7 +930,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( let infcx = selcx.infcx(); for predicate in env_predicates { debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); - if let ty::PredicateKind::Projection(data) = predicate.kind() { + if let &ty::PredicateKind::Projection(data) = predicate.kind() { let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; let is_match = same_def_id @@ -1167,12 +1167,10 @@ fn confirm_object_candidate<'cx, 'tcx>( // select only those projections that are actually projecting an // item with the correct name let env_predicates = env_predicates.filter_map(|o| match o.predicate.kind() { - ty::PredicateKind::Projection(data) => { - if data.projection_def_id() == obligation.predicate.item_def_id { - Some(data) - } else { - None - } + &ty::PredicateKind::Projection(data) + if data.projection_def_id() == obligation.predicate.item_def_id => + { + Some(data) } _ => None, }); diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 59d85281d633b..0574da38f56bf 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -414,13 +414,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.predicate.kind() { - ty::PredicateKind::Trait(ref t, _) => { + ty::PredicateKind::Trait(t, _) => { debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(*t); self.evaluate_trait_predicate_recursively(previous_stack, obligation) } - ty::PredicateKind::Subtype(ref p) => { + ty::PredicateKind::Subtype(p) => { // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { mut obligations, .. })) => { @@ -435,7 +435,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::WellFormed(ty) => match wf::obligations( + &ty::PredicateKind::WellFormed(ty) => match wf::obligations( self.infcx, obligation.param_env, obligation.cause.body_id, @@ -454,7 +454,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(EvaluatedToOkModuloRegions) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { + &ty::PredicateKind::ObjectSafe(trait_def_id) => { if self.tcx().is_object_safe(trait_def_id) { Ok(EvaluatedToOk) } else { @@ -462,7 +462,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Projection(ref data) => { + ty::PredicateKind::Projection(data) => { let project_obligation = obligation.with(*data); match project::poly_project_and_unify_type(self, &project_obligation) { Ok(Some(mut subobligations)) => { @@ -483,7 +483,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::ClosureKind(_, closure_substs, kind) => { + &ty::PredicateKind::ClosureKind(_, closure_substs, kind) => { match self.infcx.closure_kind(closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { @@ -496,7 +496,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { match self.tcx().const_eval_resolve( obligation.param_env, def_id, diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 1d89ba4efe0ac..5118859765ed7 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -73,28 +73,28 @@ pub fn predicate_obligations<'a, 'tcx>( // (*) ok to skip binders, because wf code is prepared for it match predicate.kind() { - ty::PredicateKind::Trait(ref t, _) => { + ty::PredicateKind::Trait(t, _) => { wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) } ty::PredicateKind::RegionOutlives(..) => {} - ty::PredicateKind::TypeOutlives(ref t) => { + ty::PredicateKind::TypeOutlives(t) => { wf.compute(t.skip_binder().0); } - ty::PredicateKind::Projection(ref t) => { + ty::PredicateKind::Projection(t) => { let t = t.skip_binder(); // (*) wf.compute_projection(t.projection_ty); wf.compute(t.ty); } - ty::PredicateKind::WellFormed(t) => { + &ty::PredicateKind::WellFormed(t) => { wf.compute(t); } ty::PredicateKind::ObjectSafe(_) => {} ty::PredicateKind::ClosureKind(..) => {} - ty::PredicateKind::Subtype(ref data) => { + ty::PredicateKind::Subtype(data) => { wf.compute(data.skip_binder().a); // (*) wf.compute(data.skip_binder().b); // (*) } - ty::PredicateKind::ConstEvaluatable(def_id, substs) => { + &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3526a1b59f384..9a5fe9552d35a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1605,7 +1605,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|item| item.def_id), ); } - ty::PredicateKind::Projection(pred) => { + &ty::PredicateKind::Projection(pred) => { // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. let references_self = diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 705bace4a9ccc..2a1c6b895ce20 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -597,7 +597,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); let trait_pred = match obligation.predicate.kind() { - ty::PredicateKind::Trait(trait_pred, _) + &ty::PredicateKind::Trait(trait_pred, _) if traits.contains(&trait_pred.def_id()) => { if unsize_did == trait_pred.def_id() { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 3843b97f23d41..594cdab852fda 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -232,10 +232,10 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); match (predicate.kind(), p.kind()) { (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => { - relator.relate(&a, &b).is_ok() + relator.relate(a, b).is_ok() } (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => { - relator.relate(&a, &b).is_ok() + relator.relate(a, b).is_ok() } _ => predicate == p, } From 3dd830b70ccb2d6937857e07470a5c15dd574ddd Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 20:23:15 +0200 Subject: [PATCH 089/695] ptr eq for `Predicate` --- src/librustc_middle/ty/mod.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 6bb47a8f30e74..9e8456689094f 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1016,14 +1016,23 @@ impl<'tcx> GenericPredicates<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Lift)] +#[derive(Clone, Copy, Hash, RustcEncodable, RustcDecodable, Lift)] #[derive(HashStable)] pub struct Predicate<'tcx> { kind: &'tcx PredicateKind<'tcx>, } -impl Predicate<'tcx> { - pub fn kind(&self) -> &'tcx PredicateKind<'tcx> { +impl<'tcx> PartialEq for Predicate<'tcx> { + fn eq(&self, other: &Self) -> bool { + // `self.kind` is always interned. + ptr::eq(self.kind, other.kind) + } +} + +impl<'tcx> Eq for Predicate<'tcx> {} + +impl<'tcx> Predicate<'tcx> { + pub fn kind(self) -> &'tcx PredicateKind<'tcx> { self.kind } } @@ -1098,7 +1107,7 @@ impl<'tcx> Predicate<'tcx> { /// substitution in terms of what happens with bound regions. See /// lengthy comment below for details. pub fn subst_supertrait( - &self, + self, tcx: TyCtxt<'tcx>, trait_ref: &ty::PolyTraitRef<'tcx>, ) -> ty::Predicate<'tcx> { @@ -1369,7 +1378,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { } impl<'tcx> Predicate<'tcx> { - pub fn to_opt_poly_trait_ref(&self) -> Option> { + pub fn to_opt_poly_trait_ref(self) -> Option> { match self.kind() { &PredicateKind::Trait(ref t, _) => Some(t.to_poly_trait_ref()), PredicateKind::Projection(..) @@ -1384,7 +1393,7 @@ impl<'tcx> Predicate<'tcx> { } } - pub fn to_opt_type_outlives(&self) -> Option> { + pub fn to_opt_type_outlives(self) -> Option> { match self.kind() { &PredicateKind::TypeOutlives(data) => Some(data), PredicateKind::Trait(..) From 091239ee6081d266ae59cc0660cc177994eba8d0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 11 May 2020 22:06:41 +0200 Subject: [PATCH 090/695] introduce newtype'd `Predicate<'tcx>` --- clippy_lints/src/future_not_send.rs | 2 +- clippy_lints/src/methods/mod.rs | 6 +++--- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/utils/mod.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 2c2965433fd0e..0a02aa7533c17 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -91,7 +91,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FutureNotSend { cx.tcx.infer_ctxt().enter(|infcx| { for FulfillmentError { obligation, .. } in send_errors { infcx.maybe_note_obligation_cause_for_async_await(db, &obligation); - if let Trait(trait_pred, _) = obligation.predicate { + if let Trait(trait_pred, _) = obligation.predicate.kind() { let trait_ref = trait_pred.to_poly_trait_ref(); db.note(&*format!( "`{}` doesn't implement `{}`", diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 79c21d9bc0a64..810a226b50d2a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1496,8 +1496,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { if let ty::Opaque(def_id, _) = ret_ty.kind { // one of the associated types must be Self for predicate in cx.tcx.predicates_of(def_id).predicates { - match predicate { - (ty::PredicateKind::Projection(poly_projection_predicate), _) => { + match predicate.0.kind() { + ty::PredicateKind::Projection(poly_projection_predicate) => { let binder = poly_projection_predicate.ty(); let associated_type = binder.skip_binder(); @@ -1506,7 +1506,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { return; } }, - (_, _) => {}, + _ => {}, } } } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 8f94f143bae71..60c5360054334 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter().copied()) .filter(|p| !p.is_global()) .filter_map(|obligation| { - if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate { + if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate.kind() { if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars() { return None; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 3f5693d7e6809..f22473275c466 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1299,7 +1299,7 @@ pub fn is_must_use_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> boo ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.predicates_of(*def_id).predicates { - if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate { + if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) = predicate.kind() { if must_use_attr(&cx.tcx.get_attrs(poly_trait_predicate.skip_binder().trait_ref.def_id)).is_some() { return true; } From 2db7f1abf84699605a5863887484cbf587db3eb1 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 20 May 2020 16:46:30 +0300 Subject: [PATCH 091/695] Update future-not-send stderr output --- tests/ui/future_not_send.stderr | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr index d1863701bfe7c..b59dbb3e76c64 100644 --- a/tests/ui/future_not_send.stderr +++ b/tests/ui/future_not_send.stderr @@ -47,17 +47,32 @@ error: future cannot be sent between threads safely --> $DIR/future_not_send.rs:20:63 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^ + | ^^^^ future returned by `private_future2` is not `Send` | +note: captured value is not `Send` + --> $DIR/future_not_send.rs:20:26 + | +LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { + | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` +note: captured value is not `Send` + --> $DIR/future_not_send.rs:20:40 + | +LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { + | ^^^^ has type `&std::cell::Cell` which is not `Send` = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely --> $DIR/future_not_send.rs:24:43 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} - | ^ + | ^ future returned by `public_future2` is not `Send` | +note: captured value is not `Send` + --> $DIR/future_not_send.rs:24:29 + | +LL | pub async fn public_future2(rc: Rc<[u8]>) {} + | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely @@ -117,8 +132,13 @@ error: future cannot be sent between threads safely --> $DIR/future_not_send.rs:66:34 | LL | async fn unclear_future(t: T) {} - | ^ + | ^ future returned by `unclear_future` is not `Send` | +note: captured value is not `Send` + --> $DIR/future_not_send.rs:66:28 + | +LL | async fn unclear_future(t: T) {} + | ^ has type `T` which is not `Send` = note: `T` doesn't implement `std::marker::Send` error: aborting due to 8 previous errors From 6778c7a7c147385fc8a95ead842844b005409301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 20 May 2020 00:00:00 +0000 Subject: [PATCH 092/695] Show default values for debug-assertions & debug-assertions-std --- config.toml.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.toml.example b/config.toml.example index ffe907c9da97c..cf8fe4e082ac3 100644 --- a/config.toml.example +++ b/config.toml.example @@ -312,11 +312,11 @@ # Whether or not debug assertions are enabled for the compiler and standard # library. -#debug-assertions = false +#debug-assertions = debug # Whether or not debug assertions are enabled for the standard library. # Overrides the `debug-assertions` option, if defined. -#debug-assertions-std = false +#debug-assertions-std = debug-assertions # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info From eccaa0186f8fa2a432bf612b74f18a319406134c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 2 May 2020 01:59:35 +0300 Subject: [PATCH 093/695] rustc_target: Add a target spec option for static-pie support --- src/librustc_codegen_ssa/back/link.rs | 7 ++++--- src/librustc_target/spec/mod.rs | 5 +++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index d87b84f880a35..288a4a41e07f0 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1143,9 +1143,10 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { }; // Adjust the output kind to target capabilities. - let pic_exe_supported = sess.target.target.options.position_independent_executables; - let static_pic_exe_supported = false; // FIXME: Add this option to target specs. - let static_dylib_supported = sess.target.target.options.crt_static_allows_dylibs; + let opts = &sess.target.target.options; + let pic_exe_supported = opts.position_independent_executables; + let static_pic_exe_supported = opts.static_position_independent_executables; + let static_dylib_supported = opts.crt_static_allows_dylibs; match kind { LinkOutputKind::DynamicPicExe if !pic_exe_supported => LinkOutputKind::DynamicNoPicExe, LinkOutputKind::StaticPicExe if !static_pic_exe_supported => LinkOutputKind::StaticNoPicExe, diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 41c2f1d93d2c4..d92f5cdeab5a5 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -855,6 +855,8 @@ pub struct TargetOptions { /// the functions in the executable are not randomized and can be used /// during an exploit of a vulnerability in any code. pub position_independent_executables: bool, + /// Executables that are both statically linked and position-independent are supported. + pub static_position_independent_executables: bool, /// Determines if the target always requires using the PLT for indirect /// library calls or not. This controls the default value of the `-Z plt` flag. pub needs_plt: bool, @@ -1028,6 +1030,7 @@ impl Default for TargetOptions { has_rpath: false, no_default_libraries: true, position_independent_executables: false, + static_position_independent_executables: false, needs_plt: false, relro_level: RelroLevel::None, pre_link_objects: Default::default(), @@ -1432,6 +1435,7 @@ impl Target { key!(has_rpath, bool); key!(no_default_libraries, bool); key!(position_independent_executables, bool); + key!(static_position_independent_executables, bool); key!(needs_plt, bool); key!(relro_level, RelroLevel)?; key!(archive_format); @@ -1663,6 +1667,7 @@ impl ToJson for Target { target_option_val!(has_rpath); target_option_val!(no_default_libraries); target_option_val!(position_independent_executables); + target_option_val!(static_position_independent_executables); target_option_val!(needs_plt); target_option_val!(relro_level); target_option_val!(archive_format); From 96a466c3128945627c2f81ec13b8ae98be7c3749 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 2 May 2020 02:22:48 +0300 Subject: [PATCH 094/695] linker: Support `-static-pie` and `-static -shared` --- src/librustc_codegen_ssa/back/link.rs | 22 +-- src/librustc_codegen_ssa/back/linker.rs | 227 ++++++++++++------------ 2 files changed, 118 insertions(+), 131 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 288a4a41e07f0..7addfd15f1cdd 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1530,16 +1530,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - // FIXME: Support `StaticPicExe` correctly. - match link_output_kind { - LinkOutputKind::DynamicPicExe | LinkOutputKind::StaticPicExe => { - cmd.position_independent_executable() - } - LinkOutputKind::DynamicNoPicExe | LinkOutputKind::StaticNoPicExe => { - cmd.no_position_independent_executable() - } - _ => {} - } + cmd.set_output_kind(link_output_kind, out_filename); // OBJECT-FILES-NO, AUDIT-ORDER add_relro_args(cmd, sess); @@ -1568,17 +1559,6 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( tmpdir, ); - // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - // FIXME: Merge with the previous `link_output_kind` match, - // and support `StaticPicExe` and `StaticDylib` correctly. - match link_output_kind { - LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => { - cmd.build_static_executable() - } - LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => cmd.build_dylib(out_filename), - _ => {} - } - // OBJECT-FILES-NO, AUDIT-ORDER if sess.opts.cg.profile_generate.enabled() { cmd.pgo_gen(); diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index ee5bcf4b9f58b..80d1f7006847d 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -17,7 +17,7 @@ use rustc_serialize::{json, Encoder}; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_target::spec::{LinkerFlavor, LldFlavor}; +use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; /// Disables non-English messages from localized linkers. /// Such messages may cause issues with text encoding on Windows (#35785) @@ -102,6 +102,7 @@ impl LinkerInfo { /// MSVC linker (e.g., `link.exe`) is being used. pub trait Linker { fn cmd(&mut self) -> &mut Command; + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); fn link_dylib(&mut self, lib: Symbol); fn link_rust_dylib(&mut self, lib: Symbol, path: &Path); fn link_framework(&mut self, framework: Symbol); @@ -114,8 +115,6 @@ pub trait Linker { fn output_filename(&mut self, path: &Path); fn add_object(&mut self, path: &Path); fn gc_sections(&mut self, keep_metadata: bool); - fn position_independent_executable(&mut self); - fn no_position_independent_executable(&mut self); fn full_relro(&mut self); fn partial_relro(&mut self); fn no_relro(&mut self); @@ -125,8 +124,6 @@ pub trait Linker { fn debuginfo(&mut self, strip: Strip); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); - fn build_dylib(&mut self, out_filename: &Path); - fn build_static_executable(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); fn subsystem(&mut self, subsystem: &str); fn group_start(&mut self); @@ -233,12 +230,94 @@ impl<'a> GccLinker<'a> { let target_cpu = self.target_cpu; self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu)); } + + fn build_dylib(&mut self, out_filename: &Path) { + // On mac we need to tell the linker to let this library be rpathed + if self.sess.target.target.options.is_like_osx { + self.cmd.arg("-dynamiclib"); + self.linker_arg("-dylib"); + + // Note that the `osx_rpath_install_name` option here is a hack + // purely to support rustbuild right now, we should get a more + // principled solution at some point to force the compiler to pass + // the right `-Wl,-install_name` with an `@rpath` in it. + if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { + self.linker_arg("-install_name"); + let mut v = OsString::from("@rpath/"); + v.push(out_filename.file_name().unwrap()); + self.linker_arg(&v); + } + } else { + self.cmd.arg("-shared"); + if self.sess.target.target.options.is_like_windows { + // The output filename already contains `dll_suffix` so + // the resulting import library will have a name in the + // form of libfoo.dll.a + let implib_name = + out_filename.file_name().and_then(|file| file.to_str()).map(|file| { + format!( + "{}{}{}", + self.sess.target.target.options.staticlib_prefix, + file, + self.sess.target.target.options.staticlib_suffix + ) + }); + if let Some(implib_name) = implib_name { + let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); + if let Some(implib) = implib { + self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap())); + } + } + } + } + } } impl<'a> Linker for GccLinker<'a> { fn cmd(&mut self) -> &mut Command { &mut self.cmd } + + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicNoPicExe => { + if !self.is_ld { + self.cmd.arg("-no-pie"); + } + } + LinkOutputKind::DynamicPicExe => { + // `-pie` works for both gcc wrapper and ld. + self.cmd.arg("-pie"); + } + LinkOutputKind::StaticNoPicExe => { + // `-static` works for both gcc wrapper and ld. + self.cmd.arg("-static"); + if !self.is_ld { + self.cmd.arg("-no-pie"); + } + } + LinkOutputKind::StaticPicExe => { + if !self.is_ld { + // Note that combination `-static -pie` doesn't work as expected + // for the gcc wrapper, `-static` in that case suppresses `-pie`. + self.cmd.arg("-static-pie"); + } else { + // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing + // a static pie, but currently passed because gcc and clang pass them. + // The former suppresses the `INTERP` ELF header specifying dynamic linker, + // which is otherwise implicitly injected by ld (but not lld). + // The latter doesn't change anything, only ensures that everything is pic. + self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); + } + } + LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), + LinkOutputKind::StaticDylib => { + self.cmd.arg("-static"); + self.build_dylib(out_filename); + } + } + } + fn link_dylib(&mut self, lib: Symbol) { self.hint_dynamic(); self.cmd.arg(format!("-l{}", lib)); @@ -263,14 +342,6 @@ impl<'a> Linker for GccLinker<'a> { fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } - fn position_independent_executable(&mut self) { - self.cmd.arg("-pie"); - } - fn no_position_independent_executable(&mut self) { - if !self.is_ld { - self.cmd.arg("-no-pie"); - } - } fn full_relro(&mut self) { self.linker_arg("-zrelro"); self.linker_arg("-znow"); @@ -281,9 +352,6 @@ impl<'a> Linker for GccLinker<'a> { fn no_relro(&mut self) { self.linker_arg("-znorelro"); } - fn build_static_executable(&mut self) { - self.cmd.arg("-static"); - } fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { self.hint_dynamic(); @@ -419,47 +487,6 @@ impl<'a> Linker for GccLinker<'a> { } } - fn build_dylib(&mut self, out_filename: &Path) { - // On mac we need to tell the linker to let this library be rpathed - if self.sess.target.target.options.is_like_osx { - self.cmd.arg("-dynamiclib"); - self.linker_arg("-dylib"); - - // Note that the `osx_rpath_install_name` option here is a hack - // purely to support rustbuild right now, we should get a more - // principled solution at some point to force the compiler to pass - // the right `-Wl,-install_name` with an `@rpath` in it. - if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { - self.linker_arg("-install_name"); - let mut v = OsString::from("@rpath/"); - v.push(out_filename.file_name().unwrap()); - self.linker_arg(&v); - } - } else { - self.cmd.arg("-shared"); - if self.sess.target.target.options.is_like_windows { - // The output filename already contains `dll_suffix` so - // the resulting import library will have a name in the - // form of libfoo.dll.a - let implib_name = - out_filename.file_name().and_then(|file| file.to_str()).map(|file| { - format!( - "{}{}{}", - self.sess.target.target.options.staticlib_prefix, - file, - self.sess.target.target.options.staticlib_suffix - ) - }); - if let Some(implib_name) = implib_name { - let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); - if let Some(implib) = implib { - self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap())); - } - } - } - } - } - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { // Symbol visibility in object files typically takes care of this. if crate_type == CrateType::Executable @@ -583,6 +610,22 @@ impl<'a> Linker for MsvcLinker<'a> { fn cmd(&mut self) -> &mut Command { &mut self.cmd } + + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicNoPicExe + | LinkOutputKind::DynamicPicExe + | LinkOutputKind::StaticNoPicExe + | LinkOutputKind::StaticPicExe => {} + LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { + self.cmd.arg("/DLL"); + let mut arg: OsString = "/IMPLIB:".into(); + arg.push(out_filename.with_extension("dll.lib")); + self.cmd.arg(arg); + } + } + } + fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); } @@ -590,17 +633,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(path); } - fn build_dylib(&mut self, out_filename: &Path) { - self.cmd.arg("/DLL"); - let mut arg: OsString = "/IMPLIB:".into(); - arg.push(out_filename.with_extension("dll.lib")); - self.cmd.arg(arg); - } - - fn build_static_executable(&mut self) { - // noop - } - fn gc_sections(&mut self, _keep_metadata: bool) { // MSVC's ICF (Identical COMDAT Folding) link optimization is // slow for Rust and thus we disable it by default when not in @@ -633,14 +665,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(&format!("{}.lib", lib)); } - fn position_independent_executable(&mut self) { - // noop - } - - fn no_position_independent_executable(&mut self) { - // noop - } - fn full_relro(&mut self) { // noop } @@ -818,6 +842,9 @@ impl<'a> Linker for EmLinker<'a> { fn cmd(&mut self) -> &mut Command { &mut self.cmd } + + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -857,14 +884,6 @@ impl<'a> Linker for EmLinker<'a> { self.add_object(lib); } - fn position_independent_executable(&mut self) { - // noop - } - - fn no_position_independent_executable(&mut self) { - // noop - } - fn full_relro(&mut self) { // noop } @@ -926,14 +945,6 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]); } - fn build_dylib(&mut self, _out_filename: &Path) { - bug!("building dynamic library is unsupported on Emscripten") - } - - fn build_static_executable(&mut self) { - // noop - } - fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { let symbols = &self.info.exports[&crate_type]; @@ -1032,6 +1043,18 @@ impl<'a> Linker for WasmLd<'a> { &mut self.cmd } + fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicNoPicExe + | LinkOutputKind::DynamicPicExe + | LinkOutputKind::StaticNoPicExe + | LinkOutputKind::StaticPicExe => {} + LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { + self.cmd.arg("--no-entry"); + } + } + } + fn link_dylib(&mut self, lib: Symbol) { self.cmd.arg("-l").sym_arg(lib); } @@ -1060,16 +1083,12 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg(path); } - fn position_independent_executable(&mut self) {} - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} fn no_relro(&mut self) {} - fn build_static_executable(&mut self) {} - fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { self.cmd.arg("-l").sym_arg(lib); } @@ -1125,10 +1144,6 @@ impl<'a> Linker for WasmLd<'a> { fn no_default_libraries(&mut self) {} - fn build_dylib(&mut self, _out_filename: &Path) { - self.cmd.arg("--no-entry"); - } - fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { for sym in self.info.exports[&crate_type].iter() { self.cmd.arg("--export").arg(&sym); @@ -1144,8 +1159,6 @@ impl<'a> Linker for WasmLd<'a> { fn subsystem(&mut self, _subsystem: &str) {} - fn no_position_independent_executable(&mut self) {} - fn finalize(&mut self) {} // Not needed for now with LLD @@ -1208,6 +1221,8 @@ impl<'a> Linker for PtxLinker<'a> { &mut self.cmd } + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn link_rlib(&mut self, path: &Path) { self.cmd.arg("--rlib").arg(path); } @@ -1274,16 +1289,12 @@ impl<'a> Linker for PtxLinker<'a> { panic!("frameworks not supported") } - fn position_independent_executable(&mut self) {} - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} fn no_relro(&mut self) {} - fn build_static_executable(&mut self) {} - fn gc_sections(&mut self, _keep_metadata: bool) {} fn pgo_gen(&mut self) {} @@ -1296,14 +1307,10 @@ impl<'a> Linker for PtxLinker<'a> { self.sess.warn("Windows Control Flow Guard is not supported by this linker."); } - fn build_dylib(&mut self, _out_filename: &Path) {} - fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {} fn subsystem(&mut self, _subsystem: &str) {} - fn no_position_independent_executable(&mut self) {} - fn group_start(&mut self) {} fn group_end(&mut self) {} From ed1297c92a77997178ad7aadb9d0cc087d15e0af Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 May 2020 21:08:23 +0300 Subject: [PATCH 095/695] rustc_target: Avoid an inappropriate use of `post_link_objects` --- src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs | 4 +--- src/libunwind/lib.rs | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index d26efc0985952..475a33af29c79 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -1,6 +1,6 @@ use std::iter; -use super::{crt_objects, LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions}; +use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Result { const PRE_LINK_ARGS: &[&str] = &[ @@ -68,8 +68,6 @@ pub fn target() -> Result { PRE_LINK_ARGS.iter().cloned().map(String::from).collect(), )) .collect(), - // FIXME: libunwind is certainly not a CRT object, use some other option instead. - post_link_objects: crt_objects::all("libunwind.a"), override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(String::from).collect()), relax_elf_relocations: true, ..Default::default() diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 18d41be77398b..cc025da1af555 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -27,3 +27,7 @@ extern "C" {} #[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))] #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))] extern "C" {} + +#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] +#[link(name = "unwind", kind = "static-nobundle")] +extern "C" {} From ee7a35ab95e00b5015bff8af5959ce28af528ca5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 18 May 2020 00:18:50 +0300 Subject: [PATCH 096/695] Rename some types describing native libraries NativeLibrary(Kind) -> NativeLib(Kind) NativeStatic -> StaticBundle NativeStaticNobundle -> StaticNoBundle NativeFramework -> Framework NativeRawDylib -> RawDylib NativeUnknown -> Unspecified --- src/librustc_codegen_llvm/attributes.rs | 4 +- src/librustc_codegen_ssa/back/link.rs | 47 ++++++++++--------- src/librustc_codegen_ssa/base.rs | 3 +- src/librustc_codegen_ssa/lib.rs | 6 +-- src/librustc_interface/tests.rs | 44 ++++++++--------- src/librustc_metadata/native_libs.rs | 37 ++++++++------- src/librustc_metadata/rmeta/decoder.rs | 4 +- .../rmeta/decoder/cstore_impl.rs | 7 +-- src/librustc_metadata/rmeta/encoder.rs | 6 +-- src/librustc_metadata/rmeta/mod.rs | 4 +- src/librustc_middle/middle/cstore.rs | 8 ++-- src/librustc_middle/query/mod.rs | 4 +- src/librustc_middle/ty/query/mod.rs | 5 +- src/librustc_session/config.rs | 30 +++++------- src/librustc_session/options.rs | 4 +- src/librustc_session/utils.rs | 26 +++++----- 16 files changed, 117 insertions(+), 122 deletions(-) diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 64412843f6def..b67119db2b4f2 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -361,8 +361,8 @@ pub fn provide(providers: &mut Providers<'_>) { pub fn provide_extern(providers: &mut Providers<'_>) { providers.wasm_import_module_map = |tcx, cnum| { - // Build up a map from DefId to a `NativeLibrary` structure, where - // `NativeLibrary` internally contains information about + // Build up a map from DefId to a `NativeLib` structure, where + // `NativeLib` internally contains information about // `#[link(wasm_import_module = "...")]` for example. let native_libs = tcx.native_libraries(cnum); diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index d87b84f880a35..1e9559f59f1de 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1,12 +1,13 @@ use rustc_data_structures::fx::FxHashSet; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind}; +use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, Sanitizer}; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; +use rustc_session::utils::NativeLibKind; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. use rustc_session::{filesearch, Session}; @@ -327,11 +328,11 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( // metadata of the rlib we're generating somehow. for lib in codegen_results.crate_info.used_libraries.iter() { match lib.kind { - NativeLibraryKind::NativeStatic => {} - NativeLibraryKind::NativeStaticNobundle - | NativeLibraryKind::NativeFramework - | NativeLibraryKind::NativeRawDylib - | NativeLibraryKind::NativeUnknown => continue, + NativeLibKind::StaticBundle => {} + NativeLibKind::StaticNoBundle + | NativeLibKind::Framework + | NativeLibKind::RawDylib + | NativeLibKind::Unspecified => continue, } if let Some(name) = lib.name { ab.add_native_library(name); @@ -430,7 +431,7 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( // object files come from where and selectively skip them. let skip_object_files = native_libs .iter() - .any(|lib| lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)); + .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib)); ab.add_rlib( path, &name.as_str(), @@ -858,26 +859,26 @@ enum RlibFlavor { StaticlibBase, } -fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { +fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { let lib_args: Vec<_> = all_native_libs .iter() .filter(|l| relevant_lib(sess, l)) .filter_map(|lib| { let name = lib.name?; match lib.kind { - NativeLibraryKind::NativeStaticNobundle | NativeLibraryKind::NativeUnknown => { + NativeLibKind::StaticNoBundle | NativeLibKind::Unspecified => { if sess.target.target.options.is_like_msvc { Some(format!("{}.lib", name)) } else { Some(format!("-l{}", name)) } } - NativeLibraryKind::NativeFramework => { + NativeLibKind::Framework => { // ld-only syntax, since there are no frameworks in MSVC Some(format!("-framework {}", name)) } // These are included, no need to print them - NativeLibraryKind::NativeStatic | NativeLibraryKind::NativeRawDylib => None, + NativeLibKind::StaticBundle | NativeLibKind::RawDylib => None, } }) .collect(); @@ -1647,11 +1648,11 @@ fn add_local_native_libraries( None => continue, }; match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(name), - NativeLibraryKind::NativeFramework => cmd.link_framework(name), - NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(name), - NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(name, &search_path), - NativeLibraryKind::NativeRawDylib => { + NativeLibKind::Unspecified => cmd.link_dylib(name), + NativeLibKind::Framework => cmd.link_framework(name), + NativeLibKind::StaticNoBundle => cmd.link_staticlib(name), + NativeLibKind::StaticBundle => cmd.link_whole_staticlib(name, &search_path), + NativeLibKind::RawDylib => { // FIXME(#58713): Proper handling for raw dylibs. bug!("raw_dylib feature not yet implemented"); } @@ -1841,7 +1842,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; let skip_native = native_libs .iter() - .any(|lib| lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)); + .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib)); if (!are_upstream_rust_objects_already_included(sess) || ignored_for_lto(sess, &codegen_results.crate_info, cnum)) @@ -1983,9 +1984,9 @@ fn add_upstream_native_libraries( continue; } match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(name), - NativeLibraryKind::NativeFramework => cmd.link_framework(name), - NativeLibraryKind::NativeStaticNobundle => { + NativeLibKind::Unspecified => cmd.link_dylib(name), + NativeLibKind::Framework => cmd.link_framework(name), + NativeLibKind::StaticNoBundle => { // Link "static-nobundle" native libs only if the crate they originate from // is being linked statically to the current crate. If it's linked dynamically // or is an rlib already included via some other dylib crate, the symbols from @@ -1997,8 +1998,8 @@ fn add_upstream_native_libraries( // ignore statically included native libraries here as we've // already included them when we included the rust library // previously - NativeLibraryKind::NativeStatic => {} - NativeLibraryKind::NativeRawDylib => { + NativeLibKind::StaticBundle => {} + NativeLibKind::RawDylib => { // FIXME(#58713): Proper handling for raw dylibs. bug!("raw_dylib feature not yet implemented"); } @@ -2007,7 +2008,7 @@ fn add_upstream_native_libraries( } } -fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { +fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { Some(ref cfg) => rustc_attr::cfg_matches(cfg, &sess.parse_sess, None), None => true, diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 29398db6ff8a9..c6ee43a94c398 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -44,6 +44,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, EntryFnType}; +use rustc_session::utils::NativeLibKind; use rustc_session::Session; use rustc_span::Span; use rustc_symbol_mangling::test as symbol_names_test; @@ -895,7 +896,7 @@ pub fn provide_both(providers: &mut Providers<'_>) { .native_libraries(krate) .iter() .filter(|lib| { - if lib.kind != cstore::NativeLibraryKind::NativeUnknown { + if lib.kind != NativeLibKind::Unspecified { return false; } let cfg = match lib.cfg { diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 7dc09b595c36e..bd3721850f35f 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -24,7 +24,7 @@ use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLibrary}; +use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib}; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::ty::query::Providers; use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT}; @@ -112,9 +112,9 @@ pub struct CrateInfo { pub compiler_builtins: Option, pub profiler_runtime: Option, pub is_no_builtins: FxHashSet, - pub native_libraries: FxHashMap>>, + pub native_libraries: FxHashMap>>, pub crate_name: FxHashMap, - pub used_libraries: Lrc>, + pub used_libraries: Lrc>, pub link_args: Lrc>, pub used_crate_source: FxHashMap>, pub used_crates_static: Vec<(CrateNum, LibSource)>, diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 5e17660f4c60e..3b89ceff447fe 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -2,7 +2,6 @@ use crate::interface::parse_cfgspecs; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; -use rustc_middle::middle::cstore; use rustc_session::config::Strip; use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes}; @@ -11,6 +10,7 @@ use rustc_session::config::{Externs, OutputType, OutputTypes, Sanitizer, SymbolM use rustc_session::getopts; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; +use rustc_session::utils::NativeLibKind; use rustc_session::{build_session, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; @@ -300,30 +300,30 @@ fn test_native_libs_tracking_hash_different_values() { // Reference v1.libs = vec![ - (String::from("a"), None, Some(cstore::NativeStatic)), - (String::from("b"), None, Some(cstore::NativeFramework)), - (String::from("c"), None, Some(cstore::NativeUnknown)), + (String::from("a"), None, Some(NativeLibKind::StaticBundle)), + (String::from("b"), None, Some(NativeLibKind::Framework)), + (String::from("c"), None, Some(NativeLibKind::Unspecified)), ]; // Change label v2.libs = vec![ - (String::from("a"), None, Some(cstore::NativeStatic)), - (String::from("X"), None, Some(cstore::NativeFramework)), - (String::from("c"), None, Some(cstore::NativeUnknown)), + (String::from("a"), None, Some(NativeLibKind::StaticBundle)), + (String::from("X"), None, Some(NativeLibKind::Framework)), + (String::from("c"), None, Some(NativeLibKind::Unspecified)), ]; // Change kind v3.libs = vec![ - (String::from("a"), None, Some(cstore::NativeStatic)), - (String::from("b"), None, Some(cstore::NativeStatic)), - (String::from("c"), None, Some(cstore::NativeUnknown)), + (String::from("a"), None, Some(NativeLibKind::StaticBundle)), + (String::from("b"), None, Some(NativeLibKind::StaticBundle)), + (String::from("c"), None, Some(NativeLibKind::Unspecified)), ]; // Change new-name v4.libs = vec![ - (String::from("a"), None, Some(cstore::NativeStatic)), - (String::from("b"), Some(String::from("X")), Some(cstore::NativeFramework)), - (String::from("c"), None, Some(cstore::NativeUnknown)), + (String::from("a"), None, Some(NativeLibKind::StaticBundle)), + (String::from("b"), Some(String::from("X")), Some(NativeLibKind::Framework)), + (String::from("c"), None, Some(NativeLibKind::Unspecified)), ]; assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash()); @@ -345,21 +345,21 @@ fn test_native_libs_tracking_hash_different_order() { // Reference v1.libs = vec![ - (String::from("a"), None, Some(cstore::NativeStatic)), - (String::from("b"), None, Some(cstore::NativeFramework)), - (String::from("c"), None, Some(cstore::NativeUnknown)), + (String::from("a"), None, Some(NativeLibKind::StaticBundle)), + (String::from("b"), None, Some(NativeLibKind::Framework)), + (String::from("c"), None, Some(NativeLibKind::Unspecified)), ]; v2.libs = vec![ - (String::from("b"), None, Some(cstore::NativeFramework)), - (String::from("a"), None, Some(cstore::NativeStatic)), - (String::from("c"), None, Some(cstore::NativeUnknown)), + (String::from("b"), None, Some(NativeLibKind::Framework)), + (String::from("a"), None, Some(NativeLibKind::StaticBundle)), + (String::from("c"), None, Some(NativeLibKind::Unspecified)), ]; v3.libs = vec![ - (String::from("c"), None, Some(cstore::NativeUnknown)), - (String::from("a"), None, Some(cstore::NativeStatic)), - (String::from("b"), None, Some(cstore::NativeFramework)), + (String::from("c"), None, Some(NativeLibKind::Unspecified)), + (String::from("a"), None, Some(NativeLibKind::StaticBundle)), + (String::from("b"), None, Some(NativeLibKind::Framework)), ]; assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash()); diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 51c9950a5dfed..a822aec817f00 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -3,22 +3,23 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_middle::middle::cstore::{self, NativeLibrary}; +use rustc_middle::middle::cstore::NativeLib; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; +use rustc_session::utils::NativeLibKind; use rustc_session::Session; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::spec::abi::Abi; -crate fn collect(tcx: TyCtxt<'_>) -> Vec { +crate fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { tcx, libs: Vec::new() }; tcx.hir().krate().visit_all_item_likes(&mut collector); collector.process_command_line(); collector.libs } -crate fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { +crate fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None), None => true, @@ -27,7 +28,7 @@ crate fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool { struct Collector<'tcx> { tcx: TyCtxt<'tcx>, - libs: Vec, + libs: Vec, } impl ItemLikeVisitor<'tcx> for Collector<'tcx> { @@ -47,9 +48,9 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { Some(item) => item, None => continue, }; - let mut lib = NativeLibrary { + let mut lib = NativeLib { name: None, - kind: cstore::NativeUnknown, + kind: NativeLibKind::Unspecified, cfg: None, foreign_module: Some(self.tcx.hir().local_def_id(it.hir_id).to_def_id()), wasm_import_module: None, @@ -64,11 +65,11 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { None => continue, // skip like historical compilers }; lib.kind = match &*kind.as_str() { - "static" => cstore::NativeStatic, - "static-nobundle" => cstore::NativeStaticNobundle, - "dylib" => cstore::NativeUnknown, - "framework" => cstore::NativeFramework, - "raw-dylib" => cstore::NativeRawDylib, + "static" => NativeLibKind::StaticBundle, + "static-nobundle" => NativeLibKind::StaticNoBundle, + "dylib" => NativeLibKind::Unspecified, + "framework" => NativeLibKind::Framework, + "raw-dylib" => NativeLibKind::RawDylib, k => { struct_span_err!( self.tcx.sess, @@ -80,7 +81,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { .span_label(item.span(), "unknown kind") .span_label(m.span, "") .emit(); - cstore::NativeUnknown + NativeLibKind::Unspecified } }; } else if item.check_name(sym::name) { @@ -134,7 +135,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { } impl Collector<'tcx> { - fn register_native_lib(&mut self, span: Option, lib: NativeLibrary) { + fn register_native_lib(&mut self, span: Option, lib: NativeLib) { if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) { match span { Some(span) => { @@ -154,7 +155,7 @@ impl Collector<'tcx> { return; } let is_osx = self.tcx.sess.target.target.options.is_like_osx; - if lib.kind == cstore::NativeFramework && !is_osx { + if lib.kind == NativeLibKind::Framework && !is_osx { let msg = "native frameworks are only available on macOS targets"; match span { Some(span) => struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(), @@ -170,7 +171,7 @@ impl Collector<'tcx> { ) .emit(); } - if lib.kind == cstore::NativeStaticNobundle && !self.tcx.features().static_nobundle { + if lib.kind == NativeLibKind::StaticNoBundle && !self.tcx.features().static_nobundle { feature_err( &self.tcx.sess.parse_sess, sym::static_nobundle, @@ -179,7 +180,7 @@ impl Collector<'tcx> { ) .emit(); } - if lib.kind == cstore::NativeRawDylib && !self.tcx.features().raw_dylib { + if lib.kind == NativeLibKind::RawDylib && !self.tcx.features().raw_dylib { feature_err( &self.tcx.sess.parse_sess, sym::raw_dylib, @@ -255,9 +256,9 @@ impl Collector<'tcx> { if existing.is_empty() { // Add if not found let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> - let lib = NativeLibrary { + let lib = NativeLib { name: Some(Symbol::intern(new_name.unwrap_or(name))), - kind: if let Some(k) = kind { k } else { cstore::NativeUnknown }, + kind: if let Some(k) = kind { k } else { NativeLibKind::Unspecified }, cfg: None, foreign_module: None, wasm_import_module: None, diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 32149c0afd597..220d74960755f 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -23,7 +23,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::dep_graph::{self, DepNode, DepNodeExt, DepNodeIndex}; use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::{CrateSource, ExternCrate}; -use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLibrary}; +use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, interpret, Body, Promoted}; @@ -1278,7 +1278,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } - fn get_native_libraries(&self, sess: &Session) -> Vec { + fn get_native_libraries(&self, sess: &Session) -> Vec { if self.root.is_proc_macro_crate() { // Proc macro crates do not have any *target* native libraries. vec![] diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index b18272675c0b2..6b8072ec49ab5 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -13,12 +13,13 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE} use rustc_hir::definitions::DefPathTable; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata, NativeLibraryKind}; +use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata}; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::QueryConfig; use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::utils::NativeLibKind; use rustc_session::{CrateDisambiguator, Session}; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{Ident, Symbol}; @@ -246,11 +247,11 @@ pub fn provide(providers: &mut Providers<'_>) { // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) { - Some(NativeLibraryKind::NativeUnknown | NativeLibraryKind::NativeRawDylib) => true, + Some(NativeLibKind::Unspecified | NativeLibKind::RawDylib) => true, _ => false, }, is_statically_included_foreign_item: |tcx, id| match tcx.native_library_kind(id) { - Some(NativeLibraryKind::NativeStatic | NativeLibraryKind::NativeStaticNobundle) => true, + Some(NativeLibKind::StaticBundle | NativeLibKind::StaticNoBundle) => true, _ => false, }, native_library_kind: |tcx, id| { diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 2589e162dffe2..ebe91d3cee2aa 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -18,9 +18,7 @@ use rustc_hir::lang_items; use rustc_hir::{AnonConst, GenericParamKind}; use rustc_index::vec::Idx; use rustc_middle::hir::map::Map; -use rustc_middle::middle::cstore::{ - EncodedMetadata, ForeignModule, LinkagePreference, NativeLibrary, -}; +use rustc_middle::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportLevel, @@ -1355,7 +1353,7 @@ impl EncodeContext<'tcx> { self.encode_promoted_mir(def_id); } - fn encode_native_libraries(&mut self) -> Lazy<[NativeLibrary]> { + fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> { let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); self.lazy(used_libraries.iter().cloned()) } diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 669307612055a..89d525eb80b8c 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, DefIndex}; use rustc_hir::lang_items; use rustc_index::vec::IndexVec; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLibrary}; +use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; use rustc_middle::ty::{self, ReprOptions, Ty}; @@ -190,7 +190,7 @@ crate struct CrateRoot<'tcx> { lang_items: Lazy<[(DefIndex, usize)]>, lang_items_missing: Lazy<[lang_items::LangItem]>, diagnostic_items: Lazy<[(Symbol, DefIndex)]>, - native_libraries: Lazy<[NativeLibrary]>, + native_libraries: Lazy<[NativeLib]>, foreign_modules: Lazy<[ForeignModule]>, source_map: Lazy<[rustc_span::SourceFile]>, def_path_table: Lazy, diff --git a/src/librustc_middle/middle/cstore.rs b/src/librustc_middle/middle/cstore.rs index 012390e8f74b8..97e877df96663 100644 --- a/src/librustc_middle/middle/cstore.rs +++ b/src/librustc_middle/middle/cstore.rs @@ -2,8 +2,6 @@ //! are *mostly* used as a part of that interface, but these should //! probably get a better home if someone can find one. -pub use self::NativeLibraryKind::*; - use crate::ty::TyCtxt; use rustc_ast::ast; @@ -14,7 +12,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, DefPathTable}; use rustc_macros::HashStable; use rustc_session::search_paths::PathKind; -pub use rustc_session::utils::NativeLibraryKind; +use rustc_session::utils::NativeLibKind; use rustc_session::CrateDisambiguator; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -89,8 +87,8 @@ pub enum LinkagePreference { } #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct NativeLibrary { - pub kind: NativeLibraryKind, +pub struct NativeLib { + pub kind: NativeLibKind, pub name: Option, pub cfg: Option, pub foreign_module: Option, diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 13cf9a934b72c..f7f5c5df8d67b 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -131,7 +131,7 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } - query native_libraries(_: CrateNum) -> Lrc> { + query native_libraries(_: CrateNum) -> Lrc> { desc { "looking up the native libraries of a linked crate" } } @@ -937,7 +937,7 @@ rustc_queries! { query is_dllimport_foreign_item(_: DefId) -> bool {} query is_statically_included_foreign_item(_: DefId) -> bool {} query native_library_kind(_: DefId) - -> Option {} + -> Option {} } Linking { diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs index e1a5a766ca15a..f61fc65ce394c 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/src/librustc_middle/ty/query/mod.rs @@ -4,8 +4,8 @@ use crate::hir::map; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::cstore::{CrateSource, DepKind, NativeLibraryKind}; -use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLibrary}; +use crate::middle::cstore::{CrateSource, DepKind}; +use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::AccessLevels; @@ -46,6 +46,7 @@ use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate}; use rustc_index::vec::IndexVec; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; +use rustc_session::utils::NativeLibKind; use rustc_session::CrateDisambiguator; use rustc_target::spec::PanicStrategy; diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 5f34a39db05ce..405a058ffab60 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -5,7 +5,7 @@ pub use crate::options::*; use crate::lint; use crate::search_paths::SearchPath; -use crate::utils::NativeLibraryKind; +use crate::utils::NativeLibKind; use crate::{early_error, early_warn, Session}; use rustc_data_structures::fx::FxHashSet; @@ -1452,7 +1452,7 @@ fn select_debuginfo( fn parse_libs( matches: &getopts::Matches, error_format: ErrorOutputType, -) -> Vec<(String, Option, Option)> { +) -> Vec<(String, Option, Option)> { matches .opt_strs("l") .into_iter() @@ -1463,12 +1463,10 @@ fn parse_libs( let kind = parts.next().unwrap(); let (name, kind) = match (parts.next(), kind) { (None, name) => (name, None), - (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)), - (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)), - (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)), - (Some(name), "static-nobundle") => { - (name, Some(NativeLibraryKind::NativeStaticNobundle)) - } + (Some(name), "dylib") => (name, Some(NativeLibKind::Unspecified)), + (Some(name), "framework") => (name, Some(NativeLibKind::Framework)), + (Some(name), "static") => (name, Some(NativeLibKind::StaticBundle)), + (Some(name), "static-nobundle") => (name, Some(NativeLibKind::StaticNoBundle)), (_, s) => { early_error( error_format, @@ -1480,9 +1478,7 @@ fn parse_libs( ); } }; - if kind == Some(NativeLibraryKind::NativeStaticNobundle) - && !nightly_options::is_nightly_build() - { + if kind == Some(NativeLibKind::StaticNoBundle) && !nightly_options::is_nightly_build() { early_error( error_format, "the library kind 'static-nobundle' is only \ @@ -2003,7 +1999,7 @@ crate mod dep_tracking { SymbolManglingVersion, }; use crate::lint; - use crate::utils::NativeLibraryKind; + use crate::utils::NativeLibKind; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel}; @@ -2062,7 +2058,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); - impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(CrateType); impl_dep_tracking_hash_via_hash!(MergeFunctions); impl_dep_tracking_hash_via_hash!(PanicStrategy); @@ -2073,7 +2069,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(DebugInfo); impl_dep_tracking_hash_via_hash!(UnstableFeatures); impl_dep_tracking_hash_via_hash!(OutputTypes); - impl_dep_tracking_hash_via_hash!(NativeLibraryKind); + impl_dep_tracking_hash_via_hash!(NativeLibKind); impl_dep_tracking_hash_via_hash!(Sanitizer); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(CFGuard); @@ -2088,11 +2084,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); impl_dep_tracking_hash_for_sortable_vec_of!(CrateType); impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); - impl_dep_tracking_hash_for_sortable_vec_of!(( - String, - Option, - Option - )); + impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, Option)); impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index a8d213a8663c1..5ac5cf9f6bc6f 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -3,7 +3,7 @@ use crate::config::*; use crate::early_error; use crate::lint; use crate::search_paths::SearchPath; -use crate::utils::NativeLibraryKind; +use crate::utils::NativeLibKind; use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}; use rustc_target::spec::{RelocModel, RelroLevel, TargetTriple, TlsModel}; @@ -93,7 +93,7 @@ top_level_options!( describe_lints: bool [UNTRACKED], output_types: OutputTypes [TRACKED], search_paths: Vec [UNTRACKED], - libs: Vec<(String, Option, Option)> [TRACKED], + libs: Vec<(String, Option, Option)> [TRACKED], maybe_sysroot: Option [UNTRACKED], target_triple: TargetTriple [TRACKED], diff --git a/src/librustc_session/utils.rs b/src/librustc_session/utils.rs index fda11b647490f..758a00ecdf612 100644 --- a/src/librustc_session/utils.rs +++ b/src/librustc_session/utils.rs @@ -11,17 +11,19 @@ impl Session { } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub enum NativeLibraryKind { - /// native static library (.a archive) - NativeStatic, - /// native static library, which doesn't get bundled into .rlibs - NativeStaticNobundle, - /// macOS-specific - NativeFramework, - /// Windows dynamic library without import library. - NativeRawDylib, - /// default way to specify a dynamic library - NativeUnknown, +pub enum NativeLibKind { + /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included + /// when linking a final binary, but not when archiving an rlib. + StaticNoBundle, + /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included + /// when linking a final binary, but also included when archiving an rlib. + StaticBundle, + /// Windows dynamic library (`foo.dll`) without a corresponding import library. + RawDylib, + /// A macOS-specific kind of dynamic libraries. + Framework, + /// The library kind wasn't specified, dynamic linking is currently preferred. + Unspecified, } -rustc_data_structures::impl_stable_hash_via_hash!(NativeLibraryKind); +rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind); From 529d488f1a8a009fc2dca911b25c82269fadc1d6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 18 May 2020 01:37:24 +0300 Subject: [PATCH 097/695] Factor out `NativeLibKind::Dylib` from `NativeLibKind::Unspecified` --- src/librustc_codegen_ssa/back/link.rs | 9 ++++++--- src/librustc_codegen_ssa/base.rs | 2 +- src/librustc_metadata/native_libs.rs | 2 +- src/librustc_metadata/rmeta/decoder/cstore_impl.rs | 4 +++- src/librustc_session/config.rs | 2 +- src/librustc_session/utils.rs | 7 +++++-- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 1e9559f59f1de..afff061468bc3 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -330,6 +330,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( match lib.kind { NativeLibKind::StaticBundle => {} NativeLibKind::StaticNoBundle + | NativeLibKind::Dylib | NativeLibKind::Framework | NativeLibKind::RawDylib | NativeLibKind::Unspecified => continue, @@ -866,7 +867,9 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { .filter_map(|lib| { let name = lib.name?; match lib.kind { - NativeLibKind::StaticNoBundle | NativeLibKind::Unspecified => { + NativeLibKind::StaticNoBundle + | NativeLibKind::Dylib + | NativeLibKind::Unspecified => { if sess.target.target.options.is_like_msvc { Some(format!("{}.lib", name)) } else { @@ -1648,7 +1651,7 @@ fn add_local_native_libraries( None => continue, }; match lib.kind { - NativeLibKind::Unspecified => cmd.link_dylib(name), + NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name), NativeLibKind::Framework => cmd.link_framework(name), NativeLibKind::StaticNoBundle => cmd.link_staticlib(name), NativeLibKind::StaticBundle => cmd.link_whole_staticlib(name, &search_path), @@ -1984,7 +1987,7 @@ fn add_upstream_native_libraries( continue; } match lib.kind { - NativeLibKind::Unspecified => cmd.link_dylib(name), + NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name), NativeLibKind::Framework => cmd.link_framework(name), NativeLibKind::StaticNoBundle => { // Link "static-nobundle" native libs only if the crate they originate from diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index c6ee43a94c398..ed5448ca8bac4 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -896,7 +896,7 @@ pub fn provide_both(providers: &mut Providers<'_>) { .native_libraries(krate) .iter() .filter(|lib| { - if lib.kind != NativeLibKind::Unspecified { + if !matches!(lib.kind, NativeLibKind::Dylib | NativeLibKind::Unspecified) { return false; } let cfg = match lib.cfg { diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index a822aec817f00..68ad987065710 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -67,7 +67,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { lib.kind = match &*kind.as_str() { "static" => NativeLibKind::StaticBundle, "static-nobundle" => NativeLibKind::StaticNoBundle, - "dylib" => NativeLibKind::Unspecified, + "dylib" => NativeLibKind::Dylib, "framework" => NativeLibKind::Framework, "raw-dylib" => NativeLibKind::RawDylib, k => { diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index 6b8072ec49ab5..1b168bf01178c 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -247,7 +247,9 @@ pub fn provide(providers: &mut Providers<'_>) { // resolve! Does this work? Unsure! That's what the issue is about *providers = Providers { is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) { - Some(NativeLibKind::Unspecified | NativeLibKind::RawDylib) => true, + Some(NativeLibKind::Dylib | NativeLibKind::RawDylib | NativeLibKind::Unspecified) => { + true + } _ => false, }, is_statically_included_foreign_item: |tcx, id| match tcx.native_library_kind(id) { diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 405a058ffab60..1aac639f9236e 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1463,7 +1463,7 @@ fn parse_libs( let kind = parts.next().unwrap(); let (name, kind) = match (parts.next(), kind) { (None, name) => (name, None), - (Some(name), "dylib") => (name, Some(NativeLibKind::Unspecified)), + (Some(name), "dylib") => (name, Some(NativeLibKind::Dylib)), (Some(name), "framework") => (name, Some(NativeLibKind::Framework)), (Some(name), "static") => (name, Some(NativeLibKind::StaticBundle)), (Some(name), "static-nobundle") => (name, Some(NativeLibKind::StaticNoBundle)), diff --git a/src/librustc_session/utils.rs b/src/librustc_session/utils.rs index 758a00ecdf612..b97308c22cb7d 100644 --- a/src/librustc_session/utils.rs +++ b/src/librustc_session/utils.rs @@ -18,11 +18,14 @@ pub enum NativeLibKind { /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included /// when linking a final binary, but also included when archiving an rlib. StaticBundle, - /// Windows dynamic library (`foo.dll`) without a corresponding import library. + /// Dynamic library (e.g. `libfoo.so` on Linux) + /// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC). + Dylib, + /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library. RawDylib, /// A macOS-specific kind of dynamic libraries. Framework, - /// The library kind wasn't specified, dynamic linking is currently preferred. + /// The library kind wasn't specified, `Dylib` is currently used as a default. Unspecified, } From 8dbe4d9ba4c5cd30e12179bc51c03fafd551914a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 18 May 2020 01:52:34 +0300 Subject: [PATCH 098/695] Eliminate some `Option`s --- src/librustc_interface/tests.rs | 42 ++++++++++++++-------------- src/librustc_metadata/native_libs.rs | 6 ++-- src/librustc_session/config.rs | 17 ++++++----- src/librustc_session/options.rs | 2 +- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 3b89ceff447fe..0394821d09569 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -300,30 +300,30 @@ fn test_native_libs_tracking_hash_different_values() { // Reference v1.libs = vec![ - (String::from("a"), None, Some(NativeLibKind::StaticBundle)), - (String::from("b"), None, Some(NativeLibKind::Framework)), - (String::from("c"), None, Some(NativeLibKind::Unspecified)), + (String::from("a"), None, NativeLibKind::StaticBundle), + (String::from("b"), None, NativeLibKind::Framework), + (String::from("c"), None, NativeLibKind::Unspecified), ]; // Change label v2.libs = vec![ - (String::from("a"), None, Some(NativeLibKind::StaticBundle)), - (String::from("X"), None, Some(NativeLibKind::Framework)), - (String::from("c"), None, Some(NativeLibKind::Unspecified)), + (String::from("a"), None, NativeLibKind::StaticBundle), + (String::from("X"), None, NativeLibKind::Framework), + (String::from("c"), None, NativeLibKind::Unspecified), ]; // Change kind v3.libs = vec![ - (String::from("a"), None, Some(NativeLibKind::StaticBundle)), - (String::from("b"), None, Some(NativeLibKind::StaticBundle)), - (String::from("c"), None, Some(NativeLibKind::Unspecified)), + (String::from("a"), None, NativeLibKind::StaticBundle), + (String::from("b"), None, NativeLibKind::StaticBundle), + (String::from("c"), None, NativeLibKind::Unspecified), ]; // Change new-name v4.libs = vec![ - (String::from("a"), None, Some(NativeLibKind::StaticBundle)), - (String::from("b"), Some(String::from("X")), Some(NativeLibKind::Framework)), - (String::from("c"), None, Some(NativeLibKind::Unspecified)), + (String::from("a"), None, NativeLibKind::StaticBundle), + (String::from("b"), Some(String::from("X")), NativeLibKind::Framework), + (String::from("c"), None, NativeLibKind::Unspecified), ]; assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash()); @@ -345,21 +345,21 @@ fn test_native_libs_tracking_hash_different_order() { // Reference v1.libs = vec![ - (String::from("a"), None, Some(NativeLibKind::StaticBundle)), - (String::from("b"), None, Some(NativeLibKind::Framework)), - (String::from("c"), None, Some(NativeLibKind::Unspecified)), + (String::from("a"), None, NativeLibKind::StaticBundle), + (String::from("b"), None, NativeLibKind::Framework), + (String::from("c"), None, NativeLibKind::Unspecified), ]; v2.libs = vec![ - (String::from("b"), None, Some(NativeLibKind::Framework)), - (String::from("a"), None, Some(NativeLibKind::StaticBundle)), - (String::from("c"), None, Some(NativeLibKind::Unspecified)), + (String::from("b"), None, NativeLibKind::Framework), + (String::from("a"), None, NativeLibKind::StaticBundle), + (String::from("c"), None, NativeLibKind::Unspecified), ]; v3.libs = vec![ - (String::from("c"), None, Some(NativeLibKind::Unspecified)), - (String::from("a"), None, Some(NativeLibKind::StaticBundle)), - (String::from("b"), None, Some(NativeLibKind::Framework)), + (String::from("c"), None, NativeLibKind::Unspecified), + (String::from("a"), None, NativeLibKind::StaticBundle), + (String::from("b"), None, NativeLibKind::Framework), ]; assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash()); diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 68ad987065710..fc4235a3eda09 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -241,8 +241,8 @@ impl Collector<'tcx> { .drain_filter(|lib| { if let Some(lib_name) = lib.name { if lib_name.as_str() == *name { - if let Some(k) = kind { - lib.kind = k; + if kind != NativeLibKind::Unspecified { + lib.kind = kind; } if let &Some(ref new_name) = new_name { lib.name = Some(Symbol::intern(new_name)); @@ -258,7 +258,7 @@ impl Collector<'tcx> { let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> let lib = NativeLib { name: Some(Symbol::intern(new_name.unwrap_or(name))), - kind: if let Some(k) = kind { k } else { NativeLibKind::Unspecified }, + kind, cfg: None, foreign_module: None, wasm_import_module: None, diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 1aac639f9236e..5bdd7b67723b8 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1452,7 +1452,7 @@ fn select_debuginfo( fn parse_libs( matches: &getopts::Matches, error_format: ErrorOutputType, -) -> Vec<(String, Option, Option)> { +) -> Vec<(String, Option, NativeLibKind)> { matches .opt_strs("l") .into_iter() @@ -1462,11 +1462,11 @@ fn parse_libs( let mut parts = s.splitn(2, '='); let kind = parts.next().unwrap(); let (name, kind) = match (parts.next(), kind) { - (None, name) => (name, None), - (Some(name), "dylib") => (name, Some(NativeLibKind::Dylib)), - (Some(name), "framework") => (name, Some(NativeLibKind::Framework)), - (Some(name), "static") => (name, Some(NativeLibKind::StaticBundle)), - (Some(name), "static-nobundle") => (name, Some(NativeLibKind::StaticNoBundle)), + (None, name) => (name, NativeLibKind::Unspecified), + (Some(name), "dylib") => (name, NativeLibKind::Dylib), + (Some(name), "framework") => (name, NativeLibKind::Framework), + (Some(name), "static") => (name, NativeLibKind::StaticBundle), + (Some(name), "static-nobundle") => (name, NativeLibKind::StaticNoBundle), (_, s) => { early_error( error_format, @@ -1478,7 +1478,7 @@ fn parse_libs( ); } }; - if kind == Some(NativeLibKind::StaticNoBundle) && !nightly_options::is_nightly_build() { + if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() { early_error( error_format, "the library kind 'static-nobundle' is only \ @@ -2058,7 +2058,6 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); - impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(CrateType); impl_dep_tracking_hash_via_hash!(MergeFunctions); impl_dep_tracking_hash_via_hash!(PanicStrategy); @@ -2084,7 +2083,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); impl_dep_tracking_hash_for_sortable_vec_of!(CrateType); impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); - impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, Option)); + impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, NativeLibKind)); impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 5ac5cf9f6bc6f..3b6c21e7de008 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -93,7 +93,7 @@ top_level_options!( describe_lints: bool [UNTRACKED], output_types: OutputTypes [TRACKED], search_paths: Vec [UNTRACKED], - libs: Vec<(String, Option, Option)> [TRACKED], + libs: Vec<(String, Option, NativeLibKind)> [TRACKED], maybe_sysroot: Option [UNTRACKED], target_triple: TargetTriple [TRACKED], From 633293fc3a54247f4308507632040424356a9e19 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 May 2020 15:33:58 -0400 Subject: [PATCH 099/695] Fix tests --- src/test/ui/proc-macro/break-token-spans.rs | 2 +- src/test/ui/suggestions/issue-61963.rs | 1 + src/test/ui/suggestions/issue-61963.stderr | 10 ++++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/test/ui/proc-macro/break-token-spans.rs b/src/test/ui/proc-macro/break-token-spans.rs index ce8b9ebb4f9d2..59dc3b5043cd7 100644 --- a/src/test/ui/proc-macro/break-token-spans.rs +++ b/src/test/ui/proc-macro/break-token-spans.rs @@ -2,7 +2,7 @@ // Regression test for issues #68489 and #70987 // Tests that we properly break tokens in `probably_equal_for_proc_macro` // See #72306 -// +// // Note that the weird spacing in this example is critical // for testing the issue. diff --git a/src/test/ui/suggestions/issue-61963.rs b/src/test/ui/suggestions/issue-61963.rs index c9d738f5a283e..666fc965f02f5 100644 --- a/src/test/ui/suggestions/issue-61963.rs +++ b/src/test/ui/suggestions/issue-61963.rs @@ -16,6 +16,7 @@ pub struct Qux(T); #[dom_struct] pub struct Foo { + //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects] qux: Qux>, bar: Box, //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects] diff --git a/src/test/ui/suggestions/issue-61963.stderr b/src/test/ui/suggestions/issue-61963.stderr index 0e2eb7616cf9d..62ae5fa3fe54f 100644 --- a/src/test/ui/suggestions/issue-61963.stderr +++ b/src/test/ui/suggestions/issue-61963.stderr @@ -1,5 +1,5 @@ error: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-61963.rs:20:14 + --> $DIR/issue-61963.rs:21:14 | LL | bar: Box, | ^^^ help: use `dyn`: `dyn Bar` @@ -10,5 +10,11 @@ note: the lint level is defined here LL | #![deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-61963.rs:18:1 + | +LL | pub struct Foo { + | ^^^ help: use `dyn`: `dyn pub` + +error: aborting due to 2 previous errors From dc3de7cb2ae9d886ddac91d71f2e9517ff123e90 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Wed, 20 May 2020 16:49:31 -0400 Subject: [PATCH 100/695] Add fast-path optimization for Ipv4Addr::fmt --- src/libstd/net/ip.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index edc28033c9b83..6e2478b8308af 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -856,16 +856,23 @@ impl From for IpAddr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv4Addr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address - let mut buf = [0u8; IPV4_BUF_LEN]; - let mut buf_slice = &mut buf[..]; let octets = self.octets(); - // Note: The call to write should never fail, hence the unwrap - write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap(); - let len = IPV4_BUF_LEN - buf_slice.len(); - // This unsafe is OK because we know what is being written to the buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - fmt.pad(buf) + // Fast Path: if there's no alignment stuff, write directly to the buffer + if fmt.precision().is_none() && fmt.width().is_none() { + write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]) + } else { + const IPV4_BUF_LEN: usize = 15; // Long enough for the longest possible IPv4 address + let mut buf = [0u8; IPV4_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + + // Note: The call to write should never fail, hence the unwrap + write!(buf_slice, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap(); + let len = IPV4_BUF_LEN - buf_slice.len(); + + // This unsafe is OK because we know what is being written to the buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + fmt.pad(buf) + } } } From 119efbcbfb42115adf04db98cf3fad20e13d25d9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 20 May 2020 13:58:41 -0700 Subject: [PATCH 101/695] Use `is_const_fn_raw` when unsafety checking --- src/librustc_mir/transform/check_unsafety.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 9bcb45f6493d1..a335fa2de411b 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -14,7 +14,7 @@ use rustc_span::symbol::{sym, Symbol}; use std::ops::Bound; -use crate::const_eval::{is_const_fn, is_min_const_fn}; +use crate::const_eval::is_min_const_fn; use crate::util; pub struct UnsafetyChecker<'a, 'tcx> { @@ -527,7 +527,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckRe let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) { hir::BodyOwnerKind::Closure => (false, false), hir::BodyOwnerKind::Fn => { - (is_const_fn(tcx, def_id.to_def_id()), is_min_const_fn(tcx, def_id.to_def_id())) + (tcx.is_const_fn_raw(def_id.to_def_id()), is_min_const_fn(tcx, def_id.to_def_id())) } hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false), }; From 09619bc4592418aa66a77bf90c6c2efbd648d103 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Wed, 20 May 2020 14:55:38 -0700 Subject: [PATCH 102/695] Add regression test for #72394 --- src/test/ui/unsafe/unsafe-unstable-const-fn.rs | 13 +++++++++++++ src/test/ui/unsafe/unsafe-unstable-const-fn.stderr | 11 +++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/test/ui/unsafe/unsafe-unstable-const-fn.rs create mode 100644 src/test/ui/unsafe/unsafe-unstable-const-fn.stderr diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs new file mode 100644 index 0000000000000..d9d85ee913266 --- /dev/null +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs @@ -0,0 +1,13 @@ +#![stable(feature = "foo", since = "1.33.0")] +#![feature(staged_api)] +#![feature(const_compare_raw_pointers)] +#![feature(const_fn)] + +#[stable(feature = "foo", since = "1.33.0")] +#[rustc_const_unstable(feature = "const_foo", issue = "none")] +const fn unstable(a: *const i32, b: *const i32) -> bool { + a == b + //~^ pointer operation is unsafe +} + +fn main() {} diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr new file mode 100644 index 0000000000000..d8f3737c8f541 --- /dev/null +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr @@ -0,0 +1,11 @@ +error[E0133]: pointer operation is unsafe and requires unsafe function or block + --> $DIR/unsafe-unstable-const-fn.rs:9:5 + | +LL | a == b + | ^^^^^^ pointer operation + | + = note: operations on pointers in constants + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. From 9c97b3cbf16584385111cf6f2c41d4482f41a6cd Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 7 May 2020 17:27:08 -0700 Subject: [PATCH 103/695] Move the target libLLVM to llvm-tools-preview For running the compiler, we usually only need LLVM from `$sysroot/lib`, which rustup will make available with `LD_LIBRARY_PATH`. We've also been shipping LLVM in the `$target/lib` directory, which bloats the download and installed size. The only times we do need the latter are for the RPATH of `llvm-tools-preview` binaries, and for linking `rustc-dev` libraries. We'll move it to the `llvm-tools-preview` component directly, and `rustc-dev` will have an implicit dependency on it. Here are the dist sizes that I got before and after this change: llvm-tools-1.45.0-dev-x86_64-unknown-linux-gnu.tar.gz 1.3M 24M llvm-tools-1.45.0-dev-x86_64-unknown-linux-gnu.tar.xz 748K 17M rustc-1.45.0-dev-x86_64-unknown-linux-gnu.tar.gz 83M 61M rustc-1.45.0-dev-x86_64-unknown-linux-gnu.tar.xz 56M 41M The installed size should reduce by exactly one `libLLVM.so` (~70-80M), unless you also install `llvm-tools`, and then it should be identical. --- src/bootstrap/compile.rs | 3 ++- src/bootstrap/dist.rs | 47 ++++++++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 0c754936bc242..65ba81ad4597f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -772,7 +772,8 @@ impl Step for Assemble { // Ensure that `libLLVM.so` ends up in the newly build compiler directory, // so that it can be found when the newly built `rustc` is run. - dist::maybe_install_llvm_dylib(builder, target_compiler.host, &sysroot); + dist::maybe_install_llvm_runtime(builder, target_compiler.host, &sysroot); + dist::maybe_install_llvm_target(builder, target_compiler.host, &sysroot); // Link the compiler binary itself into place let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index c4bca4a004089..5e966d7055bf3 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -514,7 +514,7 @@ impl Step for Rustc { // components like the llvm tools and LLD. LLD is included below and // tools/LLDB come later, so let's just throw it in the rustc // component for now. - maybe_install_llvm_dylib(builder, host, image); + maybe_install_llvm_runtime(builder, host, image); // Copy over lld if it's there if builder.config.lld_enabled { @@ -2228,27 +2228,18 @@ impl Step for HashSign { } } -// Maybe add libLLVM.so to the lib-dir. It will only have been built if -// LLVM tools are linked dynamically. -// -// We add this to both the libdir of the rustc binary itself (for it to load at -// runtime) and also to the target directory so it can find it at link-time. -// -// Note: This function does no yet support Windows but we also don't support -// linking LLVM tools dynamically on Windows yet. -pub fn maybe_install_llvm_dylib(builder: &Builder<'_>, target: Interned, sysroot: &Path) { +/// Maybe add libLLVM.so to the given destination lib-dir. It will only have +/// been built if LLVM tools are linked dynamically. +/// +/// Note: This function does not yet support Windows, but we also don't support +/// linking LLVM tools dynamically on Windows yet. +fn maybe_install_llvm(builder: &Builder<'_>, target: Interned, dst_libdir: &Path) { let src_libdir = builder.llvm_out(target).join("lib"); - let dst_libdir1 = sysroot.join("lib/rustlib").join(&*target).join("lib"); - let dst_libdir2 = - sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target })); - t!(fs::create_dir_all(&dst_libdir1)); - t!(fs::create_dir_all(&dst_libdir2)); if target.contains("apple-darwin") { let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); if llvm_dylib_path.exists() { - builder.install(&llvm_dylib_path, &dst_libdir1, 0o644); - builder.install(&llvm_dylib_path, &dst_libdir2, 0o644); + builder.install(&llvm_dylib_path, dst_libdir, 0o644); } return; } @@ -2262,11 +2253,23 @@ pub fn maybe_install_llvm_dylib(builder: &Builder<'_>, target: Interned, panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e); }); - builder.install(&llvm_dylib_path, &dst_libdir1, 0o644); - builder.install(&llvm_dylib_path, &dst_libdir2, 0o644); + builder.install(&llvm_dylib_path, dst_libdir, 0o644); } } +/// Maybe add libLLVM.so to the target lib-dir for linking. +pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: Interned, sysroot: &Path) { + let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib"); + maybe_install_llvm(builder, target, &dst_libdir); +} + +/// Maybe add libLLVM.so to the runtime lib-dir for rustc itself. +pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned, sysroot: &Path) { + let dst_libdir = + sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target })); + maybe_install_llvm(builder, target, &dst_libdir); +} + #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct LlvmTools { pub target: Interned, @@ -2314,6 +2317,12 @@ impl Step for LlvmTools { builder.install(&exe, &dst_bindir, 0o755); } + // Copy libLLVM.so to the target lib dir as well, so the RPATH like + // `$ORIGIN/../lib` can find it. It may also be used as a dependency + // of `rustc-dev` to support the inherited `-lLLVM` when using the + // compiler libraries. + maybe_install_llvm_target(builder, target, &image); + // Prepare the overlay let overlay = tmp.join("llvm-tools-overlay"); drop(fs::remove_dir_all(&overlay)); From a05acbf36f5a1f49919253281fc9bf9465606070 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 21 May 2020 01:10:52 +0100 Subject: [PATCH 104/695] Comment flock usage on Linux --- src/librustc_data_structures/flock.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 655248e0f5221..9383be474fd5a 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -12,6 +12,11 @@ use std::io; use std::path::Path; cfg_if! { + // We use `flock` rather than `fcntl` on Linux, because WSL1 does not support + // `fcntl`-style advisory locks properly (rust-lang/rust#72157). + // + // For other Unix targets we still use `fcntl` because it's more portable than + // `flock`. if #[cfg(target_os = "linux")] { use std::os::unix::prelude::*; From 44ca3da9a386665834e34d27e30ed471253f2777 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Wed, 20 May 2020 21:10:02 -0400 Subject: [PATCH 105/695] Various minor improvements to Ipv6Addr::Display - Defer to Ipv4Addr::fmt when printing an Ipv4 address - Fast path: write directly to f without an intermediary buffer when there are no alignment options - Simplify finding the inner zeroes-span --- src/libstd/net/ip.rs | 158 +++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 80 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index edc28033c9b83..d50230a8859a1 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -7,9 +7,9 @@ )] use crate::cmp::Ordering; -use crate::fmt; +use crate::fmt::{self, Write as FmtWrite}; use crate::hash; -use crate::io::Write; +use crate::io::Write as IoWrite; use crate::sys::net::netc as c; use crate::sys_common::{AsInner, FromInner}; @@ -1525,102 +1525,100 @@ impl Ipv6Addr { } } +/// Write an Ipv6Addr, conforming to the canonical style described by +/// [RFC 5952](https://tools.ietf.org/html/rfc5952). #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv6Addr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - // Note: The calls to write should never fail, hence the unwraps in the function - // Long enough for the longest possible IPv6: 39 - const IPV6_BUF_LEN: usize = 39; - let mut buf = [0u8; IPV6_BUF_LEN]; - let mut buf_slice = &mut buf[..]; + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // If there are no alignment requirements, write out the IP address to + // f. Otherwise, write it to a local buffer, then use f.pad. + if f.precision().is_none() && f.width().is_none() { + let segments = self.segments(); + + // Special case for :: and ::1; otherwise they get written with the + // IPv4 formatter + if self.is_unspecified() { + f.write_str("::") + } else if self.is_loopback() { + f.write_str("::1") + } else if let Some(ipv4) = self.to_ipv4() { + match segments[5] { + // IPv4 Compatible address + 0 => write!(f, "::{}", ipv4), + // IPv4 Mapped address + 0xffff => write!(f, "::ffff:{}", ipv4), + _ => unreachable!(), + } + } else { + #[derive(Copy, Clone, Default)] + struct Span { + start: usize, + len: usize, + } - match self.segments() { - // We need special cases for :: and ::1, otherwise they're formatted - // as ::0.0.0.[01] - [0, 0, 0, 0, 0, 0, 0, 0] => write!(buf_slice, "::").unwrap(), - [0, 0, 0, 0, 0, 0, 0, 1] => write!(buf_slice, "::1").unwrap(), - // Ipv4 Compatible address - [0, 0, 0, 0, 0, 0, g, h] => { - write!( - buf_slice, - "::{}.{}.{}.{}", - (g >> 8) as u8, - g as u8, - (h >> 8) as u8, - h as u8 - ) - .unwrap(); - } - // Ipv4-Mapped address - [0, 0, 0, 0, 0, 0xffff, g, h] => { - write!( - buf_slice, - "::ffff:{}.{}.{}.{}", - (g >> 8) as u8, - g as u8, - (h >> 8) as u8, - h as u8 - ) - .unwrap(); - } - _ => { - fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) { - let mut longest_span_len = 0; - let mut longest_span_at = 0; - let mut cur_span_len = 0; - let mut cur_span_at = 0; - - for i in 0..8 { - if segments[i] == 0 { - if cur_span_len == 0 { - cur_span_at = i; + // Find the inner 0 span + let zeroes = { + let mut longest = Span::default(); + let mut current = Span::default(); + + for (i, &segment) in segments.iter().enumerate() { + if segment == 0 { + if current.len == 0 { + current.start = i; } - cur_span_len += 1; + current.len += 1; - if cur_span_len > longest_span_len { - longest_span_len = cur_span_len; - longest_span_at = cur_span_at; + if current.len > longest.len { + longest = current; } } else { - cur_span_len = 0; - cur_span_at = 0; + current = Span::default(); } } - (longest_span_at, longest_span_len) - } - - let (zeros_at, zeros_len) = find_zero_slice(&self.segments()); - - if zeros_len > 1 { - fn fmt_subslice(segments: &[u16], buf: &mut &mut [u8]) { - if !segments.is_empty() { - write!(*buf, "{:x}", segments[0]).unwrap(); - for &seg in &segments[1..] { - write!(*buf, ":{:x}", seg).unwrap(); - } + longest + }; + + /// Write a colon-separated part of the address + #[inline] + fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result { + if let Some(first) = chunk.first() { + fmt::LowerHex::fmt(first, f)?; + for segment in &chunk[1..] { + f.write_char(':')?; + fmt::LowerHex::fmt(segment, f)?; } } + Ok(()) + } - fmt_subslice(&self.segments()[..zeros_at], &mut buf_slice); - write!(buf_slice, "::").unwrap(); - fmt_subslice(&self.segments()[zeros_at + zeros_len..], &mut buf_slice); + if zeroes.len > 1 { + fmt_subslice(f, &segments[..zeroes.start])?; + f.write_str("::")?; + fmt_subslice(f, &segments[zeroes.start + zeroes.len..]) } else { - let &[a, b, c, d, e, f, g, h] = &self.segments(); - write!( - buf_slice, - "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", - a, b, c, d, e, f, g, h - ) - .unwrap(); + fmt_subslice(f, &segments) } } + } else { + // Slow path: write the address to a local buffer, the use f.pad. + // Defined recursively by using the fast path to write to the + // buffer. + + // This is the largest possible size of an IPv6 address + const IPV6_BUF_LEN: usize = (4 * 8) + 7; + let mut buf = [0u8; IPV6_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + + // Note: This call to write should never fail, so unwrap is okay. + write!(buf_slice, "{}", self).unwrap(); + let len = IPV6_BUF_LEN - buf_slice.len(); + + // This is safe because we know exactly what can be in this buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + f.pad(buf) } - let len = IPV6_BUF_LEN - buf_slice.len(); - // This is safe because we know exactly what can be in this buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - fmt.pad(buf) } } From 96f387920c21a83fa620b1838066fd4c73c4b486 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Wed, 20 May 2020 23:46:57 -0400 Subject: [PATCH 106/695] impl Step for char Enables Range to be iterable Note: https://rust.godbolt.org/z/fdveKo An iteration over all char ('\0'..=char::MAX) includes unreachable panic code currently. Updating RangeInclusive::next to call Step::forward_unchecked (which is safe to do but not done yet becuase it wasn't necessary) successfully removes the panic from this iteration. --- src/libcore/iter/range.rs | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index d74df82bddd9d..6837aab7af1a2 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -1,3 +1,4 @@ +use crate::char; use crate::convert::TryFrom; use crate::mem; use crate::ops::{self, Add, Sub, Try}; @@ -400,6 +401,69 @@ step_integer_impls! { wider than usize: [u32 i32], [u64 i64], [u128 i128]; } +#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +unsafe impl Step for char { + #[inline] + fn steps_between(&start: &char, &end: &char) -> Option { + let start = start as u32; + let end = end as u32; + if start <= end { + let count = end - start + 1; + if start < 0xD800 && 0xE000 <= end { + usize::try_from(count - 0x800).ok() + } else { + usize::try_from(count).ok() + } + } else { + None + } + } + + #[inline] + fn forward_checked(start: char, count: usize) -> Option { + let start = start as u32; + let mut res = Step::forward_checked(start, count)?; + if start < 0xD800 && 0xD800 <= res { + res = Step::forward_checked(res, 0x800)?; + } + if res <= char::MAX as u32 { + Some(unsafe { char::from_u32_unchecked(res) }) + } else { + None + } + } + + #[inline] + fn backward_checked(start: char, count: usize) -> Option { + let start = start as u32; + let mut res = Step::backward_checked(start, count)?; + if start >= 0xE000 && 0xE000 > res { + res = Step::backward_checked(res, 0x800)?; + } + Some(unsafe { char::from_u32_unchecked(res) }) + } + + #[inline] + unsafe fn forward_unchecked(start: char, count: usize) -> char { + let start = start as u32; + let mut res = Step::forward_unchecked(start, count); + if start < 0xD800 && 0xD800 <= res { + res = Step::forward_unchecked(res, 0x800); + } + char::from_u32_unchecked(res) + } + + #[inline] + unsafe fn backward_unchecked(start: char, count: usize) -> char { + let start = start as u32; + let mut res = Step::backward_unchecked(start, count); + if start >= 0xE000 && 0xE000 > res { + res = Step::backward_unchecked(res, 0x800); + } + char::from_u32_unchecked(res) + } +} + macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] From c25b82f5bb9770374db31906dedb497034a151fd Mon Sep 17 00:00:00 2001 From: CAD97 Date: Wed, 20 May 2020 23:50:28 -0400 Subject: [PATCH 107/695] Use Step::forward_unchecked in RangeInclusive::next --- src/libcore/iter/range.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 6837aab7af1a2..3fa4cf2ca0da6 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -646,7 +646,11 @@ impl Iterator for ops::RangeInclusive { } let is_iterating = self.start < self.end; Some(if is_iterating { - let n = Step::forward(self.start.clone(), 1); + // SAFETY: just checked precondition + // We use the unchecked version here, because + // otherwise `for _ in '\0'..=char::MAX` + // does not successfully remove panicking code. + let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; mem::replace(&mut self.start, n) } else { self.exhausted = true; From 20b499c60a5778b9ad00c807fe33d225c36c095e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 21 May 2020 12:22:03 +0200 Subject: [PATCH 108/695] Fix anchor display when hovering impl --- src/librustdoc/html/static/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index ab52475172333..2cb3347135c1b 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -625,7 +625,7 @@ a { display: initial; } -.in-band:hover > .anchor { +.in-band:hover > .anchor, .impl:hover > .anchor { display: inline-block; position: absolute; } From bd9b09e29396697874f63d82926b36fa154caa1f Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 18 May 2020 20:54:09 +0200 Subject: [PATCH 109/695] Adapt compile-test to run tests for cargo lints --- tests/compile-test.rs | 140 ++++++++++++++++++------ tests/ui-cargo/update-all-references.sh | 18 +++ tests/ui-cargo/update-references.sh | 38 +++++++ 3 files changed, 164 insertions(+), 32 deletions(-) create mode 100755 tests/ui-cargo/update-all-references.sh create mode 100755 tests/ui-cargo/update-references.sh diff --git a/tests/compile-test.rs b/tests/compile-test.rs index a3df9d5ccbd16..91b9c73c9d47a 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -101,49 +101,124 @@ fn run_mode(cfg: &mut compiletest::Config) { compiletest::run_tests(&cfg); } -#[allow(clippy::identity_conversion)] -fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec) -> Result { - let mut result = true; - let opts = compiletest::test_opts(config); - for dir in fs::read_dir(&config.src_base)? { - let dir = dir?; - if !dir.file_type()?.is_dir() { - continue; - } - let dir_path = dir.path(); - set_var("CARGO_MANIFEST_DIR", &dir_path); - for file in fs::read_dir(&dir_path)? { - let file = file?; - let file_path = file.path(); - if file.file_type()?.is_dir() { +fn run_ui_toml(config: &mut compiletest::Config) { + fn run_tests(config: &compiletest::Config, mut tests: Vec) -> Result { + let mut result = true; + let opts = compiletest::test_opts(config); + for dir in fs::read_dir(&config.src_base)? { + let dir = dir?; + if !dir.file_type()?.is_dir() { continue; } - if file_path.extension() != Some(OsStr::new("rs")) { - continue; + let dir_path = dir.path(); + set_var("CARGO_MANIFEST_DIR", &dir_path); + for file in fs::read_dir(&dir_path)? { + let file = file?; + let file_path = file.path(); + if file.file_type()?.is_dir() { + continue; + } + if file_path.extension() != Some(OsStr::new("rs")) { + continue; + } + let paths = compiletest::common::TestPaths { + file: file_path, + base: config.src_base.clone(), + relative_dir: dir_path.file_name().unwrap().into(), + }; + let test_name = compiletest::make_test_name(&config, &paths); + let index = tests + .iter() + .position(|test| test.desc.name == test_name) + .expect("The test should be in there"); + result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?; } - let paths = compiletest::common::TestPaths { - file: file_path, - base: config.src_base.clone(), - relative_dir: dir_path.file_name().unwrap().into(), - }; - let test_name = compiletest::make_test_name(&config, &paths); - let index = tests - .iter() - .position(|test| test.desc.name == test_name) - .expect("The test should be in there"); - result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?; } + Ok(result) } - Ok(result) -} -fn run_ui_toml(config: &mut compiletest::Config) { config.mode = TestMode::Ui; config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap(); let tests = compiletest::make_tests(&config); - let res = run_ui_toml_tests(&config, tests); + let res = run_tests(&config, tests); + match res { + Ok(true) => {}, + Ok(false) => panic!("Some tests failed"), + Err(e) => { + println!("I/O failure during tests: {:?}", e); + }, + } +} + +fn run_ui_cargo(config: &mut compiletest::Config) { + fn run_tests( + config: &compiletest::Config, + filter: &Option, + mut tests: Vec, + ) -> Result { + let mut result = true; + let opts = compiletest::test_opts(config); + + for dir in fs::read_dir(&config.src_base)? { + let dir = dir?; + if !dir.file_type()?.is_dir() { + continue; + } + + // Use the filter if provided + let dir_path = dir.path(); + match &filter { + Some(name) if !dir_path.ends_with(name) => continue, + _ => {}, + } + + for case in &["pass", "fail"] { + let tail: PathBuf = [case, "src"].iter().collect(); + let src_path = dir_path.join(tail); + env::set_current_dir(&src_path)?; + + for file in fs::read_dir(&src_path)? { + let file = file?; + if file.file_type()?.is_dir() { + continue; + } + + // Search for the main file to avoid running a test for each file in the project + let file_path = file.path(); + match file_path.file_name().and_then(OsStr::to_str) { + Some("main.rs") => {}, + _ => continue, + } + + let paths = compiletest::common::TestPaths { + file: file_path, + base: config.src_base.clone(), + relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(), + }; + let test_name = compiletest::make_test_name(&config, &paths); + let index = tests + .iter() + .position(|test| test.desc.name == test_name) + .expect("The test should be in there"); + result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?; + } + } + } + Ok(result) + } + + config.mode = TestMode::Ui; + config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap(); + + let tests = compiletest::make_tests(&config); + + let current_dir = env::current_dir().unwrap(); + let filter = env::var("TESTNAME").ok(); + let res = run_tests(&config, &filter, tests); + env::set_current_dir(current_dir).unwrap(); + match res { Ok(true) => {}, Ok(false) => panic!("Some tests failed"), @@ -165,4 +240,5 @@ fn compile_test() { let mut config = default_config(); run_mode(&mut config); run_ui_toml(&mut config); + run_ui_cargo(&mut config); } diff --git a/tests/ui-cargo/update-all-references.sh b/tests/ui-cargo/update-all-references.sh new file mode 100755 index 0000000000000..7028b251ea030 --- /dev/null +++ b/tests/ui-cargo/update-all-references.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# A script to update the references for all tests. The idea is that +# you do a run, which will generate files in the build directory +# containing the (normalized) actual output of the compiler. You then +# run this script, which will copy those files over. If you find +# yourself manually editing a foo.stderr file, you're doing it wrong. +# +# See all `update-references.sh`, if you just want to update a single test. + +if [[ "$1" == "--help" || "$1" == "-h" ]]; then + echo "usage: $0" +fi + +BUILD_DIR=$PWD/target/debug/test_build_base +MY_DIR=$(dirname "$0") +cd "$MY_DIR" || exit +find . -name '*.rs' -exec ./update-references.sh "$BUILD_DIR" {} + diff --git a/tests/ui-cargo/update-references.sh b/tests/ui-cargo/update-references.sh new file mode 100755 index 0000000000000..50d42678734e9 --- /dev/null +++ b/tests/ui-cargo/update-references.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# A script to update the references for particular tests. The idea is +# that you do a run, which will generate files in the build directory +# containing the (normalized) actual output of the compiler. This +# script will then copy that output and replace the "expected output" +# files. You can then commit the changes. +# +# If you find yourself manually editing a foo.stderr file, you're +# doing it wrong. + +if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then + echo "usage: $0 " + echo "" + echo "For example:" + echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" +fi + +MYDIR=$(dirname "$0") + +BUILD_DIR="$1" +shift + +while [[ "$1" != "" ]]; do + STDERR_NAME="${1/%.rs/.stderr}" + STDOUT_NAME="${1/%.rs/.stdout}" + shift + if [[ -f "$BUILD_DIR"/"$STDOUT_NAME" ]] && \ + ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then + echo updating "$MYDIR"/"$STDOUT_NAME" + cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME" + fi + if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \ + ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then + echo updating "$MYDIR"/"$STDERR_NAME" + cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME" + fi +done From 96af3e83601a6cd37544e70a7a816c36cc9871f5 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 18 May 2020 20:55:12 +0200 Subject: [PATCH 110/695] Add test for wildcard_dependencies --- tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml | 6 ++++++ tests/ui-cargo/wildcard_dependencies/fail/src/main.rs | 3 +++ tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr | 6 ++++++ tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml | 6 ++++++ tests/ui-cargo/wildcard_dependencies/pass/src/main.rs | 3 +++ 5 files changed, 24 insertions(+) create mode 100644 tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml create mode 100644 tests/ui-cargo/wildcard_dependencies/fail/src/main.rs create mode 100644 tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr create mode 100644 tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml create mode 100644 tests/ui-cargo/wildcard_dependencies/pass/src/main.rs diff --git a/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml b/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml new file mode 100644 index 0000000000000..9558dd680918b --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "wildcard_dependencies" +version = "0.1.0" + +[dependencies] +regex = "*" diff --git a/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs new file mode 100644 index 0000000000000..3491ccb0d47d5 --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::wildcard_dependencies)] + +fn main() {} diff --git a/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr b/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr new file mode 100644 index 0000000000000..9e65d2f99420a --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr @@ -0,0 +1,6 @@ +error: wildcard dependency for `regex` + | + = note: `-D clippy::wildcard-dependencies` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml b/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml new file mode 100644 index 0000000000000..062e441622a8d --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "wildcard_dependencies" +version = "0.1.0" + +[dependencies] +regex = "1" diff --git a/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs new file mode 100644 index 0000000000000..3491ccb0d47d5 --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::wildcard_dependencies)] + +fn main() {} From bc93f7052e4a76d62e2aa5f11649e662cb46c7ce Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 18 May 2020 20:56:33 +0200 Subject: [PATCH 111/695] Add test for cargo_common_metadata Fix missing `authors` entry in the provided example --- clippy_lints/src/cargo_common_metadata.rs | 1 + .../cargo_common_metadata/fail/Cargo.toml | 3 +++ .../cargo_common_metadata/fail/src/main.rs | 3 +++ .../cargo_common_metadata/fail/src/main.stderr | 18 ++++++++++++++++++ .../cargo_common_metadata/pass/Cargo.toml | 10 ++++++++++ .../cargo_common_metadata/pass/src/main.rs | 3 +++ 6 files changed, 38 insertions(+) create mode 100644 tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml create mode 100644 tests/ui-cargo/cargo_common_metadata/fail/src/main.rs create mode 100644 tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr create mode 100644 tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml create mode 100644 tests/ui-cargo/cargo_common_metadata/pass/src/main.rs diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 782da249808d0..16b46423c8f01 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -23,6 +23,7 @@ declare_clippy_lint! { /// [package] /// name = "clippy" /// version = "0.0.212" + /// authors = ["Someone "] /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" /// repository = "https://github.com/rust-lang/rust-clippy" /// readme = "README.md" diff --git a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml new file mode 100644 index 0000000000000..8346bf0577839 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs new file mode 100644 index 0000000000000..c67166fc4b007 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr new file mode 100644 index 0000000000000..c8ae6c820df9d --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr @@ -0,0 +1,18 @@ +error: package `cargo_common_metadata` is missing `package.authors` metadata + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + +error: package `cargo_common_metadata` is missing `package.description` metadata + +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata + +error: package `cargo_common_metadata` is missing `package.repository` metadata + +error: package `cargo_common_metadata` is missing `package.readme` metadata + +error: package `cargo_common_metadata` is missing `package.keywords` metadata + +error: package `cargo_common_metadata` is missing `package.categories` metadata + +error: aborting due to 7 previous errors + diff --git a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml new file mode 100644 index 0000000000000..f99c126fabf69 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +authors = ["Random person from the Internet "] +description = "A test package for the cargo_common_metadata lint" +repository = "https://github.com/someone/cargo_common_metadata" +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["metadata", "lint", "clippy"] +categories = ["development-tools::testing"] diff --git a/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs new file mode 100644 index 0000000000000..c67166fc4b007 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::cargo_common_metadata)] + +fn main() {} From 7a0eccbd8a719af00b027b0ea85c576d9cbed750 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 18 May 2020 20:58:02 +0200 Subject: [PATCH 112/695] Add test for multiple_crate_versions Make the output of the lint deterministic by sorting the versions --- clippy_lints/src/multiple_crate_versions.rs | 4 +++- tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml | 7 +++++++ tests/ui-cargo/multiple_crate_versions/fail/src/main.rs | 3 +++ .../ui-cargo/multiple_crate_versions/fail/src/main.stderr | 6 ++++++ tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml | 7 +++++++ tests/ui-cargo/multiple_crate_versions/pass/src/main.rs | 3 +++ 6 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml create mode 100644 tests/ui-cargo/multiple_crate_versions/fail/src/main.rs create mode 100644 tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr create mode 100644 tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml create mode 100644 tests/ui-cargo/multiple_crate_versions/pass/src/main.rs diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index ed85d0315bd25..c4decfc940111 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -54,7 +54,9 @@ impl LateLintPass<'_, '_> for MultipleCrateVersions { let group: Vec = group.collect(); if group.len() > 1 { - let versions = group.into_iter().map(|p| p.version).join(", "); + let mut versions: Vec<_> = group.into_iter().map(|p| p.version).collect(); + versions.sort(); + let versions = versions.iter().join(", "); span_lint( cx, diff --git a/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml new file mode 100644 index 0000000000000..05ffde839dc1f --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "multiple_crate_versions" +version = "0.1.0" + +[dependencies] +ctrlc = "=3.1.0" +ansi_term = "=0.11.0" diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs new file mode 100644 index 0000000000000..4bc61dd62992f --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::multiple_crate_versions)] + +fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr new file mode 100644 index 0000000000000..4f668599be950 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr @@ -0,0 +1,6 @@ +error: multiple versions for dependency `winapi`: 0.2.8, 0.3.8 + | + = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml new file mode 100644 index 0000000000000..cad32b9233f48 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" + +[dependencies] +regex = "1.3.7" +serde = "1.0.110" diff --git a/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs new file mode 100644 index 0000000000000..4bc61dd62992f --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs @@ -0,0 +1,3 @@ +#![warn(clippy::multiple_crate_versions)] + +fn main() {} From 1eb6adf47579e3c56b38ba6cce7676e8d2d5beb0 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 18 May 2020 21:03:37 +0200 Subject: [PATCH 113/695] Adapt `cargo dev new_lint` to create tests for cargo lints --- clippy_dev/src/new_lint.rs | 178 ++++++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 73 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 44b2a5383d211..843beaf323877 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,91 +1,110 @@ use crate::clippy_project_root; -use std::fs::{File, OpenOptions}; -use std::io; +use std::fs::{self, OpenOptions}; use std::io::prelude::*; -use std::io::ErrorKind; -use std::path::Path; +use std::io::{self, ErrorKind}; +use std::path::{Path, PathBuf}; + +struct LintData<'a> { + pass: &'a str, + name: &'a str, + category: &'a str, + project_root: PathBuf, +} + +trait Context { + fn context>(self, text: C) -> Self; +} -/// Creates files required to implement and test a new lint and runs `update_lints`. +impl Context for io::Result { + fn context>(self, text: C) -> Self { + match self { + Err(e) => { + let message = format!("{}: {}", text.as_ref(), e); + Err(io::Error::new(ErrorKind::Other, message)) + }, + ok => ok, + } + } +} + +/// Creates the files required to implement and test a new lint and runs `update_lints`. /// /// # Errors /// -/// This function errors, if the files couldn't be created -pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> Result<(), io::Error> { - let pass = pass.expect("`pass` argument is validated by clap"); - let lint_name = lint_name.expect("`name` argument is validated by clap"); - let category = category.expect("`category` argument is validated by clap"); - - match open_files(lint_name) { - Ok((mut test_file, mut lint_file)) => { - let (pass_type, pass_lifetimes, pass_import, context_import) = match pass { - "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), - "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"), - _ => { - unreachable!("`pass_type` should only ever be `early` or `late`!"); - }, - }; - - let camel_case_name = to_camel_case(lint_name); - - if let Err(e) = test_file.write_all(get_test_file_contents(lint_name).as_bytes()) { - return Err(io::Error::new( - ErrorKind::Other, - format!("Could not write to test file: {}", e), - )); - }; - - if let Err(e) = lint_file.write_all( - get_lint_file_contents( - pass_type, - pass_lifetimes, - lint_name, - &camel_case_name, - category, - pass_import, - context_import, - ) - .as_bytes(), - ) { - return Err(io::Error::new( - ErrorKind::Other, - format!("Could not write to lint file: {}", e), - )); - } - Ok(()) +/// This function errors out if the files couldn't be created or written to. +pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> io::Result<()> { + let lint = LintData { + pass: pass.expect("`pass` argument is validated by clap"), + name: lint_name.expect("`name` argument is validated by clap"), + category: category.expect("`category` argument is validated by clap"), + project_root: clippy_project_root(), + }; + + create_lint(&lint).context("Unable to create lint implementation")?; + create_test(&lint).context("Unable to create a test for the new lint") +} + +fn create_lint(lint: &LintData) -> io::Result<()> { + let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass { + "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), + "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"), + _ => { + unreachable!("`pass_type` should only ever be `early` or `late`!"); }, - Err(e) => Err(io::Error::new( - ErrorKind::Other, - format!("Unable to create lint: {}", e), - )), - } + }; + + let camel_case_name = to_camel_case(lint.name); + let lint_contents = get_lint_file_contents( + pass_type, + pass_lifetimes, + lint.name, + &camel_case_name, + lint.category, + pass_import, + context_import, + ); + + let lint_path = format!("clippy_lints/src/{}.rs", lint.name); + write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes()) } -fn open_files(lint_name: &str) -> Result<(File, File), io::Error> { - let project_root = clippy_project_root(); +fn create_test(lint: &LintData) -> io::Result<()> { + fn create_project_layout>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> { + let mut path = location.into().join(case); + fs::create_dir(&path)?; + write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?; - let test_file_path = project_root.join("tests").join("ui").join(format!("{}.rs", lint_name)); - let lint_file_path = project_root - .join("clippy_lints") - .join("src") - .join(format!("{}.rs", lint_name)); + path.push("src"); + fs::create_dir(&path)?; + write_file(path.join("main.rs"), get_test_file_contents(lint_name))?; - if Path::new(&test_file_path).exists() { - return Err(io::Error::new( - ErrorKind::AlreadyExists, - format!("test file {:?} already exists", test_file_path), - )); + Ok(()) } - if Path::new(&lint_file_path).exists() { - return Err(io::Error::new( - ErrorKind::AlreadyExists, - format!("lint file {:?} already exists", lint_file_path), - )); + + if lint.category == "cargo" { + let relative_test_dir = format!("tests/ui-cargo/{}", lint.name); + let test_dir = lint.project_root.join(relative_test_dir); + fs::create_dir(&test_dir)?; + + create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?; + create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint") + } else { + let test_path = format!("tests/ui/{}.rs", lint.name); + let test_contents = get_test_file_contents(lint.name); + write_file(lint.project_root.join(test_path), test_contents) } +} - let test_file = OpenOptions::new().write(true).create_new(true).open(test_file_path)?; - let lint_file = OpenOptions::new().write(true).create_new(true).open(lint_file_path)?; +fn write_file, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { + fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { + OpenOptions::new() + .write(true) + .create_new(true) + .open(path)? + .write_all(contents) + } - Ok((test_file, lint_file)) + inner(path.as_ref(), contents.as_ref()).context(format!("writing to file: {}", path.as_ref().display())) } fn to_camel_case(name: &str) -> String { @@ -112,6 +131,19 @@ fn main() {{ ) } +fn get_manifest_contents(lint_name: &str, hint: &str) -> String { + format!( + r#" +# {} + +[package] +name = "{}" +version = "0.1.0" +"#, + hint, lint_name + ) +} + fn get_lint_file_contents( pass_type: &str, pass_lifetimes: &str, From 5d0135e222448e637ec1d66b3dd5c0805884dedd Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 18 May 2020 21:39:56 +0200 Subject: [PATCH 114/695] Add documentation for testing cargo lints --- doc/adding_lints.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 9ad1315c17521..75768681db93c 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -42,8 +42,10 @@ case), and we don't need type information so it will have an early pass type `cargo dev new_lint --name=foo_functions --pass=early --category=pedantic` (category will default to nursery if not provided). This command will create two files: `tests/ui/foo_functions.rs` and `clippy_lints/src/foo_functions.rs`, -as well as run `cargo dev update_lints` to register the new lint. Next, we'll -open up these files and add our lint! +as well as run `cargo dev update_lints` to register the new lint. For cargo lints, +two project hierarchies (fail/pass) will be created under `tests/ui-cargo`. + +Next, we'll open up these files and add our lint! ## Testing @@ -105,6 +107,19 @@ our lint, we need to commit the generated `.stderr` files, too. In general, you should only commit files changed by `tests/ui/update-all-references.sh` for the specific lint you are creating/editing. +### Cargo lints + +For cargo lints, the process of testing differs in that we are interested in +the contents of the `Cargo.toml` files. If our new lint is named e.g. `foo_categories`, +after running `cargo dev new_lint` we will find two new manifest files: + +* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the new lint to raise an error. +* `tests/ui-cargo/foo_categories/pass/Cargo.toml`: this file should not trigger the lint. + +The process of generating the `.stderr` file is the same, and prepending the `TESTNAME` +variable to `cargo uitest` works too, but the script to update the references +is in another path: `tests/ui-cargo/update-all-references.sh`. + ## Rustfix tests If the lint you are working on is making use of structured suggestions, the From 7ff71199df911b462800cf6bda7ac32879ba7eb1 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Thu, 21 May 2020 14:46:04 +0200 Subject: [PATCH 115/695] Address comments from PR review --- clippy_dev/src/new_lint.rs | 1 + tests/compile-test.rs | 4 ++-- tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml | 1 + tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml | 1 + tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml | 1 + tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml | 1 + tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml | 1 + tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml | 1 + 8 files changed, 9 insertions(+), 2 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 843beaf323877..80713ab569fd5 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -139,6 +139,7 @@ fn get_manifest_contents(lint_name: &str, hint: &str) -> String { [package] name = "{}" version = "0.1.0" +publish = false "#, hint, lint_name ) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 91b9c73c9d47a..232b966f69a1f 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -147,7 +147,7 @@ fn run_ui_toml(config: &mut compiletest::Config) { Ok(true) => {}, Ok(false) => panic!("Some tests failed"), Err(e) => { - println!("I/O failure during tests: {:?}", e); + panic!("I/O failure during tests: {:?}", e); }, } } @@ -223,7 +223,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) { Ok(true) => {}, Ok(false) => panic!("Some tests failed"), Err(e) => { - println!("I/O failure during tests: {:?}", e); + panic!("I/O failure during tests: {:?}", e); }, } } diff --git a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml index 8346bf0577839..c64adcf7c0131 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml @@ -1,3 +1,4 @@ [package] name = "cargo_common_metadata" version = "0.1.0" +publish = false diff --git a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml index f99c126fabf69..c8233f328bb05 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml +++ b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "cargo_common_metadata" version = "0.1.0" +publish = false authors = ["Random person from the Internet "] description = "A test package for the cargo_common_metadata lint" repository = "https://github.com/someone/cargo_common_metadata" diff --git a/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml index 05ffde839dc1f..3a94b723f3fdb 100644 --- a/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml +++ b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "multiple_crate_versions" version = "0.1.0" +publish = false [dependencies] ctrlc = "=3.1.0" diff --git a/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml index cad32b9233f48..a9b06420b333d 100644 --- a/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml +++ b/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "cargo_common_metadata" version = "0.1.0" +publish = false [dependencies] regex = "1.3.7" diff --git a/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml b/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml index 9558dd680918b..fd2a341485683 100644 --- a/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml +++ b/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "wildcard_dependencies" version = "0.1.0" +publish = false [dependencies] regex = "*" diff --git a/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml b/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml index 062e441622a8d..38cb139146e05 100644 --- a/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml +++ b/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "wildcard_dependencies" version = "0.1.0" +publish = false [dependencies] regex = "1" From 1a04686fc0d2752de8731c833ab67bfae6136720 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Thu, 21 May 2020 14:47:13 +0200 Subject: [PATCH 116/695] Avoid triggering match_wildcard_for_single_variants --- clippy_dev/src/new_lint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 80713ab569fd5..08a2e0c0918f0 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -18,11 +18,11 @@ trait Context { impl Context for io::Result { fn context>(self, text: C) -> Self { match self { + Ok(t) => Ok(t), Err(e) => { let message = format!("{}: {}", text.as_ref(), e); Err(io::Error::new(ErrorKind::Other, message)) }, - ok => ok, } } } From 34b51187ce8fa261ebe3bef4a9a26135b919ac02 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Wed, 20 May 2020 17:48:21 +0300 Subject: [PATCH 117/695] Suggest using std::mem::drop function instead of explicit destructor call --- src/librustc_typeck/check/callee.rs | 26 ++++++++++++++++--- src/librustc_typeck/check/method/confirm.rs | 9 ++++--- src/librustc_typeck/check/mod.rs | 2 +- src/test/ui/error-codes/E0040.stderr | 5 +++- .../ui/explicit/explicit-call-to-dtor.stderr | 5 +++- .../explicit-call-to-supertrait-dtor.stderr | 5 +++- src/test/ui/illegal-ufcs-drop.stderr | 5 +++- 7 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 52ddacc1c4b1a..4c31363f2c084 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -21,11 +21,29 @@ use rustc_target::spec::abi; /// Checks that it is legal to call methods of the trait corresponding /// to `trait_id` (this only cares about the trait, not the specific /// method that is called). -pub fn check_legal_trait_for_method_call(tcx: TyCtxt<'_>, span: Span, trait_id: DefId) { +pub fn check_legal_trait_for_method_call( + tcx: TyCtxt<'_>, + span: Span, + receiver: Option, + trait_id: DefId, +) { if tcx.lang_items().drop_trait() == Some(trait_id) { - struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method") - .span_label(span, "explicit destructor calls not allowed") - .emit(); + let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method"); + err.span_label(span, "explicit destructor calls not allowed"); + + let snippet = receiver + .and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok()) + .unwrap_or_default(); + + let (suggestion, applicability) = if snippet.is_empty() { + (snippet, Applicability::Unspecified) + } else { + (format!("drop({})", snippet), Applicability::MachineApplicable) + }; + + err.span_suggestion(span, "consider using `drop` function", suggestion, applicability); + + err.emit(); } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index c4805c54a7d43..38a5bd5fce00d 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -597,9 +597,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn enforce_illegal_method_limitations(&self, pick: &probe::Pick<'_>) { // Disallow calls to the method `drop` defined in the `Drop` trait. match pick.item.container { - ty::TraitContainer(trait_def_id) => { - callee::check_legal_trait_for_method_call(self.tcx, self.span, trait_def_id) - } + ty::TraitContainer(trait_def_id) => callee::check_legal_trait_for_method_call( + self.tcx, + self.span, + Some(self.self_expr.span), + trait_def_id, + ), ty::ImplContainer(..) => {} } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d72c74e4188ee..3ac3934bea32b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5438,7 +5438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); match container { ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(tcx, span, trait_did) + callee::check_legal_trait_for_method_call(tcx, span, None, trait_did) } ty::ImplContainer(impl_def_id) => { if segments.len() == 1 { diff --git a/src/test/ui/error-codes/E0040.stderr b/src/test/ui/error-codes/E0040.stderr index 966455902817d..69cf28b29704f 100644 --- a/src/test/ui/error-codes/E0040.stderr +++ b/src/test/ui/error-codes/E0040.stderr @@ -2,7 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/E0040.rs:13:7 | LL | x.drop(); - | ^^^^ explicit destructor calls not allowed + | ^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(x)` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-dtor.stderr b/src/test/ui/explicit/explicit-call-to-dtor.stderr index cbbe967179ef3..5ebe4ee4b90f8 100644 --- a/src/test/ui/explicit/explicit-call-to-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-dtor.stderr @@ -2,7 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-dtor.rs:13:7 | LL | x.drop(); - | ^^^^ explicit destructor calls not allowed + | ^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(x)` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr index 0b302e30b64f3..cd3fb3119a5cf 100644 --- a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -2,7 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-supertrait-dtor.rs:17:14 | LL | self.drop(); - | ^^^^ explicit destructor calls not allowed + | ^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(self)` error: aborting due to previous error diff --git a/src/test/ui/illegal-ufcs-drop.stderr b/src/test/ui/illegal-ufcs-drop.stderr index d35d376962c17..922d50d259569 100644 --- a/src/test/ui/illegal-ufcs-drop.stderr +++ b/src/test/ui/illegal-ufcs-drop.stderr @@ -2,7 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/illegal-ufcs-drop.rs:8:5 | LL | Drop::drop(&mut Foo) - | ^^^^^^^^^^ explicit destructor calls not allowed + | ^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function error: aborting due to previous error From f9013ff197a693798f0532f88bab0ae591d5ff82 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Thu, 21 May 2020 15:34:48 +0200 Subject: [PATCH 118/695] Relax fs layout so that multiple pass/fail manifests are possible --- doc/adding_lints.md | 11 ++++++++--- tests/compile-test.rs | 10 +++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 75768681db93c..b3f5a62d55307 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -43,7 +43,7 @@ case), and we don't need type information so it will have an early pass type (category will default to nursery if not provided). This command will create two files: `tests/ui/foo_functions.rs` and `clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to register the new lint. For cargo lints, -two project hierarchies (fail/pass) will be created under `tests/ui-cargo`. +two project hierarchies (fail/pass) will be created by default under `tests/ui-cargo`. Next, we'll open up these files and add our lint! @@ -110,12 +110,17 @@ specific lint you are creating/editing. ### Cargo lints For cargo lints, the process of testing differs in that we are interested in -the contents of the `Cargo.toml` files. If our new lint is named e.g. `foo_categories`, -after running `cargo dev new_lint` we will find two new manifest files: +the `Cargo.toml` manifest file. We also need a minimal crate associated +with that manifest. + +If our new lint is named e.g. `foo_categories`, after running `cargo dev new_lint` +we will find by default two new crates, each with its manifest file: * `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the new lint to raise an error. * `tests/ui-cargo/foo_categories/pass/Cargo.toml`: this file should not trigger the lint. +If you need more cases, you can copy one of those crates (under `foo_categories`) and rename it. + The process of generating the `.stderr` file is the same, and prepending the `TESTNAME` variable to `cargo uitest` works too, but the script to update the references is in another path: `tests/ui-cargo/update-all-references.sh`. diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 232b966f69a1f..a5de84293909f 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -174,9 +174,13 @@ fn run_ui_cargo(config: &mut compiletest::Config) { _ => {}, } - for case in &["pass", "fail"] { - let tail: PathBuf = [case, "src"].iter().collect(); - let src_path = dir_path.join(tail); + for case in fs::read_dir(&dir_path)? { + let case = case?; + if !case.file_type()?.is_dir() { + continue; + } + + let src_path = case.path().join("src"); env::set_current_dir(&src_path)?; for file in fs::read_dir(&src_path)? { From 94aa02855defad20fe63d46a5df9506e82b78ff3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 16:30:27 +0200 Subject: [PATCH 119/695] fix discriminant sign extension --- src/librustc_mir/interpret/intrinsics.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 42b969c99917f..fc4be82ad90ad 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -219,7 +219,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let place = self.deref_operand(args[0])?; let discr_val = self.read_discriminant(place.into())?.0; let scalar = match dest.layout.ty.kind { - ty::Int(_) => Scalar::from_int(discr_val as i128, dest.layout.size), + ty::Int(_) => Scalar::from_int( + self.sign_extend(discr_val, dest.layout) as i128, + dest.layout.size, + ), ty::Uint(_) => Scalar::from_uint(discr_val, dest.layout.size), _ => bug!("invalid `discriminant_value` return layout: {:?}", dest.layout), }; From 5728c5371dc27aa0572c99c692cede23a019b7ff Mon Sep 17 00:00:00 2001 From: marmeladema Date: Wed, 20 May 2020 18:35:58 +0100 Subject: [PATCH 120/695] Use `HirId` as key for `ResolverOutputs::trait_map` instead of `NodeId` --- src/librustc_hir/definitions.rs | 4 +++- src/librustc_middle/ty/context.rs | 3 +-- src/librustc_middle/ty/mod.rs | 4 ++-- src/librustc_resolve/lib.rs | 19 +++++++++++++++++-- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index 30cddac6aac91..c7a0822d27dd6 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -327,7 +327,9 @@ impl Definitions { #[inline] pub fn local_def_id(&self, node: ast::NodeId) -> LocalDefId { - self.opt_local_def_id(node).unwrap() + self.opt_local_def_id(node).unwrap_or_else(|| { + panic!("no entry for node id: `{:?}` / `{:?}`", node, self.opt_node_id_to_hir_id(node)) + }) } #[inline] diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index d2e53facf5e0a..a09d1c16986bd 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1113,8 +1113,7 @@ impl<'tcx> TyCtxt<'tcx> { }; let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (k, v) in resolutions.trait_map { - let hir_id = definitions.node_id_to_hir_id(k); + for (hir_id, v) in resolutions.trait_map.into_iter() { let map = trait_map.entry(hir_id.owner).or_default(); let v = v .into_iter() diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 36bc44f5e5032..4b9f77b4b4b57 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -31,7 +31,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::lang_items::{FnMutTraitLangItem, FnOnceTraitLangItem, FnTraitLangItem}; -use rustc_hir::{Constness, GlobMap, Node, TraitMap}; +use rustc_hir::{Constness, GlobMap, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_serialize::{self, Encodable, Encoder}; @@ -121,7 +121,7 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, pub extern_crate_map: NodeMap, - pub trait_map: TraitMap, + pub trait_map: FxHashMap>>, pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, pub export_map: ExportMap, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bfb7f081fc333..625ca5dec5083 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! This crate is responsible for the part of name resolution that doesn't require type checker. //! //! Module structure of the crate is built here. @@ -1271,12 +1273,19 @@ impl<'a> Resolver<'a> { } pub fn into_outputs(self) -> ResolverOutputs { + let trait_map = { + let mut map = FxHashMap::default(); + for (k, v) in self.trait_map.into_iter() { + map.insert(self.definitions.node_id_to_hir_id(k), v); + } + map + }; ResolverOutputs { definitions: self.definitions, cstore: Box::new(self.crate_loader.into_cstore()), extern_crate_map: self.extern_crate_map, export_map: self.export_map, - trait_map: self.trait_map, + trait_map, glob_map: self.glob_map, maybe_unused_trait_imports: self.maybe_unused_trait_imports, maybe_unused_extern_crates: self.maybe_unused_extern_crates, @@ -1294,7 +1303,13 @@ impl<'a> Resolver<'a> { cstore: Box::new(self.cstore().clone()), extern_crate_map: self.extern_crate_map.clone(), export_map: self.export_map.clone(), - trait_map: self.trait_map.clone(), + trait_map: { + let mut map = FxHashMap::default(); + for (k, v) in self.trait_map.iter() { + map.insert(self.definitions.node_id_to_hir_id(k.clone()), v.clone()); + } + map + }, glob_map: self.glob_map.clone(), maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(), From 3c5dba7c6214b2a27d4d976419ab3036ec7ae473 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Wed, 20 May 2020 21:52:30 +0100 Subject: [PATCH 121/695] Use `HirId` in value of `ResolverOutputs::trait_map` instead of `NodeId` --- src/librustc_middle/ty/context.rs | 4 ---- src/librustc_middle/ty/mod.rs | 2 +- src/librustc_resolve/lib.rs | 20 +++++++++++++++++--- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index a09d1c16986bd..8b96b0eaab3c5 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1115,10 +1115,6 @@ impl<'tcx> TyCtxt<'tcx> { let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); for (hir_id, v) in resolutions.trait_map.into_iter() { let map = trait_map.entry(hir_id.owner).or_default(); - let v = v - .into_iter() - .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id))) - .collect(); map.insert(hir_id.local_id, StableVec::new(v)); } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 4b9f77b4b4b57..46715b8e737a9 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -121,7 +121,7 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, pub extern_crate_map: NodeMap, - pub trait_map: FxHashMap>>, + pub trait_map: FxHashMap>>, pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, pub export_map: ExportMap, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 625ca5dec5083..0b6b1fbdc34a0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1273,15 +1273,21 @@ impl<'a> Resolver<'a> { } pub fn into_outputs(self) -> ResolverOutputs { + let definitions = self.definitions; let trait_map = { let mut map = FxHashMap::default(); for (k, v) in self.trait_map.into_iter() { - map.insert(self.definitions.node_id_to_hir_id(k), v); + map.insert( + definitions.node_id_to_hir_id(k), + v.into_iter() + .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id))) + .collect(), + ); } map }; ResolverOutputs { - definitions: self.definitions, + definitions: definitions, cstore: Box::new(self.crate_loader.into_cstore()), extern_crate_map: self.extern_crate_map, export_map: self.export_map, @@ -1306,7 +1312,15 @@ impl<'a> Resolver<'a> { trait_map: { let mut map = FxHashMap::default(); for (k, v) in self.trait_map.iter() { - map.insert(self.definitions.node_id_to_hir_id(k.clone()), v.clone()); + map.insert( + self.definitions.node_id_to_hir_id(k.clone()), + v.iter() + .map(|tc| { + tc.clone() + .map_import_ids(|id| self.definitions.node_id_to_hir_id(id)) + }) + .collect(), + ); } map }, From 52359f7c609ef3908c9fc6faf3d0e36f02c6d207 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Wed, 20 May 2020 22:54:12 +0100 Subject: [PATCH 122/695] Use `HirId` in `ResolverOutputs::export_map` instead of `NodeId` --- src/librustc_middle/ty/context.rs | 12 +----------- src/librustc_middle/ty/mod.rs | 2 +- src/librustc_resolve/lib.rs | 27 +++++++++++++++++++++++++-- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 8b96b0eaab3c5..fffc286c8f6f7 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1131,17 +1131,7 @@ impl<'tcx> TyCtxt<'tcx> { consts: common_consts, extern_crate_map: resolutions.extern_crate_map, trait_map, - export_map: resolutions - .export_map - .into_iter() - .map(|(k, v)| { - let exports: Vec<_> = v - .into_iter() - .map(|e| e.map_id(|id| definitions.node_id_to_hir_id(id))) - .collect(); - (k, exports) - }) - .collect(), + export_map: resolutions.export_map, maybe_unused_trait_imports: resolutions .maybe_unused_trait_imports .into_iter() diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 46715b8e737a9..820aa457d7c0f 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -124,7 +124,7 @@ pub struct ResolverOutputs { pub trait_map: FxHashMap>>, pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, - pub export_map: ExportMap, + pub export_map: ExportMap, pub glob_map: GlobMap, /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0b6b1fbdc34a0..db9af9a0c4be1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1274,6 +1274,18 @@ impl<'a> Resolver<'a> { pub fn into_outputs(self) -> ResolverOutputs { let definitions = self.definitions; + let export_map = { + let mut map = FxHashMap::default(); + for (k, v) in self.export_map.into_iter() { + map.insert( + k, + v.into_iter() + .map(|e| e.map_id(|id| definitions.node_id_to_hir_id(id))) + .collect(), + ); + } + map + }; let trait_map = { let mut map = FxHashMap::default(); for (k, v) in self.trait_map.into_iter() { @@ -1290,7 +1302,7 @@ impl<'a> Resolver<'a> { definitions: definitions, cstore: Box::new(self.crate_loader.into_cstore()), extern_crate_map: self.extern_crate_map, - export_map: self.export_map, + export_map, trait_map, glob_map: self.glob_map, maybe_unused_trait_imports: self.maybe_unused_trait_imports, @@ -1308,7 +1320,18 @@ impl<'a> Resolver<'a> { definitions: self.definitions.clone(), cstore: Box::new(self.cstore().clone()), extern_crate_map: self.extern_crate_map.clone(), - export_map: self.export_map.clone(), + export_map: { + let mut map = FxHashMap::default(); + for (k, v) in self.export_map.iter() { + map.insert( + k.clone(), + v.iter() + .map(|e| e.clone().map_id(|id| self.definitions.node_id_to_hir_id(id))) + .collect(), + ); + } + map + }, trait_map: { let mut map = FxHashMap::default(); for (k, v) in self.trait_map.iter() { From 13c86f289ba0d2944da320fd6c0359a591ce4374 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Wed, 20 May 2020 23:01:48 +0100 Subject: [PATCH 123/695] Use `LocalDefId` in `ResolverOutputs::maybe_unused_trait_imports` instead of `NodeId` --- src/librustc_middle/ty/context.rs | 6 +----- src/librustc_middle/ty/mod.rs | 5 +++-- src/librustc_resolve/lib.rs | 13 +++++++++++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index fffc286c8f6f7..d090f9235ce33 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1132,11 +1132,7 @@ impl<'tcx> TyCtxt<'tcx> { extern_crate_map: resolutions.extern_crate_map, trait_map, export_map: resolutions.export_map, - maybe_unused_trait_imports: resolutions - .maybe_unused_trait_imports - .into_iter() - .map(|id| definitions.local_def_id(id)) - .collect(), + maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports, maybe_unused_extern_crates: resolutions .maybe_unused_extern_crates .into_iter() diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 820aa457d7c0f..4dc815fa7bcd0 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -17,11 +17,12 @@ use crate::ty; use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; use rustc_ast::ast; -use rustc_ast::node_id::{NodeId, NodeMap, NodeSet}; +use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -122,7 +123,7 @@ pub struct ResolverOutputs { pub cstore: Box, pub extern_crate_map: NodeMap, pub trait_map: FxHashMap>>, - pub maybe_unused_trait_imports: NodeSet, + pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, pub export_map: ExportMap, pub glob_map: GlobMap, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index db9af9a0c4be1..21a535b85aac7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1298,6 +1298,11 @@ impl<'a> Resolver<'a> { } map }; + let maybe_unused_trait_imports = self + .maybe_unused_trait_imports + .into_iter() + .map(|id| definitions.local_def_id(id)) + .collect(); ResolverOutputs { definitions: definitions, cstore: Box::new(self.crate_loader.into_cstore()), @@ -1305,7 +1310,7 @@ impl<'a> Resolver<'a> { export_map, trait_map, glob_map: self.glob_map, - maybe_unused_trait_imports: self.maybe_unused_trait_imports, + maybe_unused_trait_imports, maybe_unused_extern_crates: self.maybe_unused_extern_crates, extern_prelude: self .extern_prelude @@ -1348,7 +1353,11 @@ impl<'a> Resolver<'a> { map }, glob_map: self.glob_map.clone(), - maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), + maybe_unused_trait_imports: self + .maybe_unused_trait_imports + .iter() + .map(|id| self.definitions.local_def_id(id.clone())) + .collect(), maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(), extern_prelude: self .extern_prelude From 25f575b29f467d2bb7aff9be359743414d218dfa Mon Sep 17 00:00:00 2001 From: marmeladema Date: Wed, 20 May 2020 23:11:56 +0100 Subject: [PATCH 124/695] Use `DefId` in `ResolverOutputs::maybe_unused_extern_crates` instead of `NodeId` --- src/librustc_middle/ty/context.rs | 6 +----- src/librustc_middle/ty/mod.rs | 4 ++-- src/librustc_resolve/lib.rs | 13 +++++++++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index d090f9235ce33..fc77df51aa855 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1133,11 +1133,7 @@ impl<'tcx> TyCtxt<'tcx> { trait_map, export_map: resolutions.export_map, maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports, - maybe_unused_extern_crates: resolutions - .maybe_unused_extern_crates - .into_iter() - .map(|(id, sp)| (definitions.local_def_id(id).to_def_id(), sp)) - .collect(), + maybe_unused_extern_crates: resolutions.maybe_unused_extern_crates, glob_map: resolutions .glob_map .into_iter() diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 4dc815fa7bcd0..550016ce81b48 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -17,7 +17,7 @@ use crate::ty; use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; use rustc_ast::ast; -use rustc_ast::node_id::{NodeId, NodeMap}; +use rustc_ast::node_id::NodeMap; use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; @@ -124,7 +124,7 @@ pub struct ResolverOutputs { pub extern_crate_map: NodeMap, pub trait_map: FxHashMap>>, pub maybe_unused_trait_imports: FxHashSet, - pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, + pub maybe_unused_extern_crates: Vec<(DefId, Span)>, pub export_map: ExportMap, pub glob_map: GlobMap, /// Extern prelude entries. The value is `true` if the entry was introduced diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 21a535b85aac7..b3a668f00ff0e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1303,6 +1303,11 @@ impl<'a> Resolver<'a> { .into_iter() .map(|id| definitions.local_def_id(id)) .collect(); + let maybe_unused_extern_crates = self + .maybe_unused_extern_crates + .into_iter() + .map(|(id, sp)| (definitions.local_def_id(id).to_def_id(), sp)) + .collect(); ResolverOutputs { definitions: definitions, cstore: Box::new(self.crate_loader.into_cstore()), @@ -1311,7 +1316,7 @@ impl<'a> Resolver<'a> { trait_map, glob_map: self.glob_map, maybe_unused_trait_imports, - maybe_unused_extern_crates: self.maybe_unused_extern_crates, + maybe_unused_extern_crates, extern_prelude: self .extern_prelude .iter() @@ -1358,7 +1363,11 @@ impl<'a> Resolver<'a> { .iter() .map(|id| self.definitions.local_def_id(id.clone())) .collect(), - maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(), + maybe_unused_extern_crates: self + .maybe_unused_extern_crates + .iter() + .map(|(id, sp)| (self.definitions.local_def_id(id.clone()).to_def_id(), sp.clone())) + .collect(), extern_prelude: self .extern_prelude .iter() From 21f65ae9db20c2019e9e4989754894d9ee7680ce Mon Sep 17 00:00:00 2001 From: marmeladema Date: Wed, 20 May 2020 23:18:45 +0100 Subject: [PATCH 125/695] Use `DefId` in `ResolverOutputs::glob_map` instead of `NodeId` --- src/librustc_middle/ty/context.rs | 6 +----- src/librustc_middle/ty/mod.rs | 4 ++-- src/librustc_resolve/lib.rs | 13 +++++++++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index fc77df51aa855..ad43f8c25b2cc 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1134,11 +1134,7 @@ impl<'tcx> TyCtxt<'tcx> { export_map: resolutions.export_map, maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports, maybe_unused_extern_crates: resolutions.maybe_unused_extern_crates, - glob_map: resolutions - .glob_map - .into_iter() - .map(|(id, names)| (definitions.local_def_id(id), names)) - .collect(), + glob_map: resolutions.glob_map, extern_prelude: resolutions.extern_prelude, untracked_crate: krate, definitions, diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 550016ce81b48..f246d8cf4c09d 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -32,7 +32,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::lang_items::{FnMutTraitLangItem, FnOnceTraitLangItem, FnTraitLangItem}; -use rustc_hir::{Constness, GlobMap, Node}; +use rustc_hir::{Constness, Node}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_serialize::{self, Encodable, Encoder}; @@ -126,7 +126,7 @@ pub struct ResolverOutputs { pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(DefId, Span)>, pub export_map: ExportMap, - pub glob_map: GlobMap, + pub glob_map: FxHashMap>, /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. pub extern_prelude: FxHashMap, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b3a668f00ff0e..03fc6a6ab4b16 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1308,13 +1308,18 @@ impl<'a> Resolver<'a> { .into_iter() .map(|(id, sp)| (definitions.local_def_id(id).to_def_id(), sp)) .collect(); + let glob_map = self + .glob_map + .into_iter() + .map(|(id, names)| (definitions.local_def_id(id), names)) + .collect(); ResolverOutputs { definitions: definitions, cstore: Box::new(self.crate_loader.into_cstore()), extern_crate_map: self.extern_crate_map, export_map, trait_map, - glob_map: self.glob_map, + glob_map, maybe_unused_trait_imports, maybe_unused_extern_crates, extern_prelude: self @@ -1357,7 +1362,11 @@ impl<'a> Resolver<'a> { } map }, - glob_map: self.glob_map.clone(), + glob_map: self + .glob_map + .iter() + .map(|(id, names)| (self.definitions.local_def_id(id.clone()), names.clone())) + .collect(), maybe_unused_trait_imports: self .maybe_unused_trait_imports .iter() From 8ff6ffd88897c29a494b1dcabd5bd98b9cde0a39 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Thu, 21 May 2020 00:08:49 +0100 Subject: [PATCH 126/695] Use `DefId` in `ResolverOutputs::extern_crate_map` instead of `NodeId` --- src/librustc_middle/ty/context.rs | 8 ++------ src/librustc_middle/ty/mod.rs | 3 +-- src/librustc_resolve/lib.rs | 17 +++++++++++++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index ad43f8c25b2cc..6a46a83a412a0 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -34,7 +34,6 @@ use crate::ty::{InferConst, ParamConst}; use crate::ty::{List, TyKind, TyS}; use rustc_ast::ast; use rustc_ast::expand::allocator::AllocatorKind; -use rustc_ast::node_id::NodeMap; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::SelfProfilerRef; @@ -923,7 +922,7 @@ pub struct GlobalCtxt<'tcx> { pub consts: CommonConsts<'tcx>, /// Resolutions of `extern crate` items produced by resolver. - extern_crate_map: NodeMap, + extern_crate_map: FxHashMap, /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. @@ -2682,10 +2681,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { let id = tcx.hir().local_def_id_to_hir_id(id.expect_local()); tcx.stability().local_deprecation_entry(id) }; - providers.extern_mod_stmt_cnum = |tcx, id| { - let id = tcx.hir().as_local_node_id(id).unwrap(); - tcx.extern_crate_map.get(&id).cloned() - }; + providers.extern_mod_stmt_cnum = |tcx, id| tcx.extern_crate_map.get(&id).cloned(); providers.all_crate_nums = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); tcx.arena.alloc_slice(&tcx.cstore.crates_untracked()) diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index f246d8cf4c09d..73b4074bd6205 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -17,7 +17,6 @@ use crate::ty; use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; use rustc_ast::ast; -use rustc_ast::node_id::NodeMap; use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; @@ -121,7 +120,7 @@ mod sty; pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, - pub extern_crate_map: NodeMap, + pub extern_crate_map: FxHashMap, pub trait_map: FxHashMap>>, pub maybe_unused_trait_imports: FxHashSet, pub maybe_unused_extern_crates: Vec<(DefId, Span)>, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 03fc6a6ab4b16..d09b5b5d701d2 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1274,6 +1274,13 @@ impl<'a> Resolver<'a> { pub fn into_outputs(self) -> ResolverOutputs { let definitions = self.definitions; + let extern_crate_map = { + let mut map = FxHashMap::default(); + for (k, v) in self.extern_crate_map.into_iter() { + map.insert(definitions.local_def_id(k).to_def_id(), v); + } + map + }; let export_map = { let mut map = FxHashMap::default(); for (k, v) in self.export_map.into_iter() { @@ -1316,7 +1323,7 @@ impl<'a> Resolver<'a> { ResolverOutputs { definitions: definitions, cstore: Box::new(self.crate_loader.into_cstore()), - extern_crate_map: self.extern_crate_map, + extern_crate_map, export_map, trait_map, glob_map, @@ -1334,7 +1341,13 @@ impl<'a> Resolver<'a> { ResolverOutputs { definitions: self.definitions.clone(), cstore: Box::new(self.cstore().clone()), - extern_crate_map: self.extern_crate_map.clone(), + extern_crate_map: { + let mut map = FxHashMap::default(); + for (k, v) in self.extern_crate_map.iter() { + map.insert(self.definitions.local_def_id(k.clone()).to_def_id(), v.clone()); + } + map + }, export_map: { let mut map = FxHashMap::default(); for (k, v) in self.export_map.iter() { From 4c4cb464912b82f08e4144b88dd4a0dc1a671a7e Mon Sep 17 00:00:00 2001 From: marmeladema Date: Thu, 21 May 2020 01:02:15 +0100 Subject: [PATCH 127/695] Use `collect()` instead of manually inserting elements into maps --- src/librustc_resolve/lib.rs | 88 ++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d09b5b5d701d2..bd4cb89939e1d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1274,37 +1274,35 @@ impl<'a> Resolver<'a> { pub fn into_outputs(self) -> ResolverOutputs { let definitions = self.definitions; - let extern_crate_map = { - let mut map = FxHashMap::default(); - for (k, v) in self.extern_crate_map.into_iter() { - map.insert(definitions.local_def_id(k).to_def_id(), v); - } - map - }; - let export_map = { - let mut map = FxHashMap::default(); - for (k, v) in self.export_map.into_iter() { - map.insert( + let extern_crate_map = self + .extern_crate_map + .into_iter() + .map(|(k, v)| (definitions.local_def_id(k).to_def_id(), v)) + .collect(); + let export_map = self + .export_map + .into_iter() + .map(|(k, v)| { + ( k, v.into_iter() .map(|e| e.map_id(|id| definitions.node_id_to_hir_id(id))) .collect(), - ); - } - map - }; - let trait_map = { - let mut map = FxHashMap::default(); - for (k, v) in self.trait_map.into_iter() { - map.insert( + ) + }) + .collect(); + let trait_map = self + .trait_map + .into_iter() + .map(|(k, v)| { + ( definitions.node_id_to_hir_id(k), v.into_iter() .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id))) .collect(), - ); - } - map - }; + ) + }) + .collect(); let maybe_unused_trait_imports = self .maybe_unused_trait_imports .into_iter() @@ -1341,29 +1339,28 @@ impl<'a> Resolver<'a> { ResolverOutputs { definitions: self.definitions.clone(), cstore: Box::new(self.cstore().clone()), - extern_crate_map: { - let mut map = FxHashMap::default(); - for (k, v) in self.extern_crate_map.iter() { - map.insert(self.definitions.local_def_id(k.clone()).to_def_id(), v.clone()); - } - map - }, - export_map: { - let mut map = FxHashMap::default(); - for (k, v) in self.export_map.iter() { - map.insert( + extern_crate_map: self + .extern_crate_map + .iter() + .map(|(k, v)| (self.definitions.local_def_id(k.clone()).to_def_id(), v.clone())) + .collect(), + export_map: self + .export_map + .iter() + .map(|(k, v)| { + ( k.clone(), v.iter() .map(|e| e.clone().map_id(|id| self.definitions.node_id_to_hir_id(id))) .collect(), - ); - } - map - }, - trait_map: { - let mut map = FxHashMap::default(); - for (k, v) in self.trait_map.iter() { - map.insert( + ) + }) + .collect(), + trait_map: self + .trait_map + .iter() + .map(|(k, v)| { + ( self.definitions.node_id_to_hir_id(k.clone()), v.iter() .map(|tc| { @@ -1371,10 +1368,9 @@ impl<'a> Resolver<'a> { .map_import_ids(|id| self.definitions.node_id_to_hir_id(id)) }) .collect(), - ); - } - map - }, + ) + }) + .collect(), glob_map: self .glob_map .iter() From f31e076d98e3b6f457f975a0dcba9c4b0f43fc91 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Thu, 21 May 2020 17:34:54 +0100 Subject: [PATCH 128/695] Replace unecessary calls to `.clone()` by argument binding pattern for `Copy` types --- src/librustc_resolve/lib.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bd4cb89939e1d..9699aff69c013 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1342,16 +1342,16 @@ impl<'a> Resolver<'a> { extern_crate_map: self .extern_crate_map .iter() - .map(|(k, v)| (self.definitions.local_def_id(k.clone()).to_def_id(), v.clone())) + .map(|(&k, &v)| (self.definitions.local_def_id(k).to_def_id(), v)) .collect(), export_map: self .export_map .iter() - .map(|(k, v)| { + .map(|(&k, v)| { ( - k.clone(), + k, v.iter() - .map(|e| e.clone().map_id(|id| self.definitions.node_id_to_hir_id(id))) + .map(|e| e.map_id(|id| self.definitions.node_id_to_hir_id(id))) .collect(), ) }) @@ -1359,13 +1359,13 @@ impl<'a> Resolver<'a> { trait_map: self .trait_map .iter() - .map(|(k, v)| { + .map(|(&k, v)| { ( - self.definitions.node_id_to_hir_id(k.clone()), + self.definitions.node_id_to_hir_id(k), v.iter() + .cloned() .map(|tc| { - tc.clone() - .map_import_ids(|id| self.definitions.node_id_to_hir_id(id)) + tc.map_import_ids(|id| self.definitions.node_id_to_hir_id(id)) }) .collect(), ) @@ -1374,17 +1374,17 @@ impl<'a> Resolver<'a> { glob_map: self .glob_map .iter() - .map(|(id, names)| (self.definitions.local_def_id(id.clone()), names.clone())) + .map(|(&id, names)| (self.definitions.local_def_id(id), names.clone())) .collect(), maybe_unused_trait_imports: self .maybe_unused_trait_imports .iter() - .map(|id| self.definitions.local_def_id(id.clone())) + .map(|&id| self.definitions.local_def_id(id)) .collect(), maybe_unused_extern_crates: self .maybe_unused_extern_crates .iter() - .map(|(id, sp)| (self.definitions.local_def_id(id.clone()).to_def_id(), sp.clone())) + .map(|&(id, sp)| (self.definitions.local_def_id(id).to_def_id(), sp)) .collect(), extern_prelude: self .extern_prelude From a81e9a781b19153d19898c421c80d713dc739d8e Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Tue, 19 May 2020 15:37:06 +0200 Subject: [PATCH 129/695] Improve documentation of `slice::from_raw_parts` This is to provide a more explicit statement against a code pattern that many people end up coming with, since the reason of it being unsound comes from the badly known single-allocation validity rule. Providing that very pattern as a counter-example could help mitigate that. Co-authored-by: Ralf Jung --- src/libcore/slice/mod.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 9582ac33ff6b7..2e1dd89433d9e 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5740,7 +5740,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. +/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. /// * `data` must be non-null and aligned even for zero-length slices. One /// reason for this is that enum layout optimizations may rely on references /// (including slices of any length) being aligned and non-null to distinguish @@ -5773,6 +5774,34 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// assert_eq!(slice[0], 42); /// ``` /// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocated objects_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocated objects... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguous in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// /// [valid]: ../../std/ptr/index.html#safety /// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset From 67e075589b7e19a87130a700b7e59015a1b80f11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 19:07:59 +0200 Subject: [PATCH 130/695] Typo --- src/libcore/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 2e1dd89433d9e..b5ce165cb43db 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5797,7 +5797,7 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { /// // `a` and `b` are different allocated objects... /// let a = 42; /// let b = 27; -/// // ... which may nevertheless be laid out contiguous in memory: | a | b | +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | /// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB /// } /// ``` From 27d1cd857e8998c423f329efce7c995a26dcdb6c Mon Sep 17 00:00:00 2001 From: CAD97 Date: Thu, 21 May 2020 13:21:55 -0400 Subject: [PATCH 131/695] Add safety annotations in iter::range --- src/libcore/iter/range.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 3fa4cf2ca0da6..5db790e491c2d 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -427,6 +427,8 @@ unsafe impl Step for char { res = Step::forward_checked(res, 0x800)?; } if res <= char::MAX as u32 { + // SAFETY: res is a valid unicode scalar + // (below 0x110000 and not in 0xD800..0xE000) Some(unsafe { char::from_u32_unchecked(res) }) } else { None @@ -440,6 +442,8 @@ unsafe impl Step for char { if start >= 0xE000 && 0xE000 > res { res = Step::backward_checked(res, 0x800)?; } + // SAFETY: res is a valid unicode scalar + // (below 0x110000 and not in 0xD800..0xE000) Some(unsafe { char::from_u32_unchecked(res) }) } From b1d1f256ef1902312803d3d1bd0235bfdf864aec Mon Sep 17 00:00:00 2001 From: CAD97 Date: Thu, 21 May 2020 13:43:01 -0400 Subject: [PATCH 132/695] Add a test for char ranges --- src/libcore/tests/iter.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 52cf068f0a567..6605249f18004 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1932,6 +1932,16 @@ fn test_range() { ); } +#[test] +fn test_char_range() { + use std::char; + assert!(('\0'..=char::MAX).eq((0..=char::MAX as u32).filter_map(char::from_u32))); + assert!(('\0'..=char::MAX).rev().eq((0..=char::MAX as u32).filter_map(char::from_u32).rev())); + + assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2); + assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1); +} + #[test] fn test_range_exhaustion() { let mut r = 10..10; From d0a48d19f5e10869ea4a137d4bb3b84d62966e31 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 21 May 2020 20:53:41 +0300 Subject: [PATCH 133/695] rustllvm: Fix warnings about unused function parameters --- src/librustc_codegen_llvm/back/write.rs | 3 --- src/librustc_codegen_llvm/context.rs | 20 +++++-------------- .../debuginfo/metadata.rs | 12 ++--------- src/librustc_codegen_llvm/debuginfo/mod.rs | 9 ++------- src/librustc_codegen_llvm/llvm/ffi.rs | 6 ------ src/rustllvm/PassWrapper.cpp | 2 +- src/rustllvm/RustWrapper.cpp | 7 ++----- 7 files changed, 12 insertions(+), 47 deletions(-) diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 6ed9cd69738cc..57e018bba6a1a 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -6,7 +6,6 @@ use crate::back::profiling::{ use crate::base; use crate::common; use crate::consts; -use crate::context::all_outputs_are_pic_executables; use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic}; use crate::llvm_util; use crate::type_::Type; @@ -150,7 +149,6 @@ pub fn target_machine_factory( let features = features.join(","); let features = CString::new(features).unwrap(); let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname); - let pic_is_pie = all_outputs_are_pic_executables(sess); let trap_unreachable = sess.target.target.options.trap_unreachable; let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; @@ -174,7 +172,6 @@ pub fn target_machine_factory( reloc_model, opt_level, use_softfp, - pic_is_pie, ffunction_sections, fdata_sections, trap_unreachable, diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 01f90cae7a5fc..3192d4fc15701 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -97,17 +97,6 @@ fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode { } } -/// PIE is potentially more effective than PIC, but can only be used in executables. -/// If all our outputs are executables, then we can relax PIC to PIE when producing object code. -/// If the list of crate types is not yet known we conservatively return `false`. -pub fn all_outputs_are_pic_executables(sess: &Session) -> bool { - sess.relocation_model() == RelocModel::Pic - && sess - .crate_types - .try_get() - .map_or(false, |crate_types| crate_types.iter().all(|ty| *ty == CrateType::Executable)) -} - fn strip_function_ptr_alignment(data_layout: String) -> String { // FIXME: Make this more general. data_layout.replace("-Fi8-", "-") @@ -183,10 +172,11 @@ pub unsafe fn create_module( if sess.relocation_model() == RelocModel::Pic { llvm::LLVMRustSetModulePICLevel(llmod); - } - - if all_outputs_are_pic_executables(sess) { - llvm::LLVMRustSetModulePIELevel(llmod); + // PIE is potentially more effective than PIC, but can only be used in executables. + // If all our outputs are executables, then we can relax PIC to PIE. + if sess.crate_types.get().iter().all(|ty| *ty == CrateType::Executable) { + llvm::LLVMRustSetModulePIELevel(llmod); + } } // If skipping the PLT is enabled, we need to add some module metadata diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index fb9a27ed001f4..0cce0b25e5893 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -447,7 +447,6 @@ fn subroutine_type_metadata( unsafe { llvm::LLVMRustDIBuilderCreateSubroutineType( DIB(cx), - unknown_file_metadata(cx), create_DIArray(DIB(cx), &signature_metadata[..]), ) }, @@ -635,14 +634,12 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp // anything reading the debuginfo for a recursive // type is going to see *something* weird - the only // question is what exactly it will see. - let (size, align) = cx.size_and_align_of(t); let name = ""; llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), name.as_ptr().cast(), name.len(), - size.bits(), - align.bits() as u32, + cx.size_of(t).bits(), DW_ATE_unsigned, ) } @@ -841,14 +838,12 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { _ => bug!("debuginfo::basic_type_metadata - `t` is invalid type"), }; - let (size, align) = cx.size_and_align_of(t); let ty_metadata = unsafe { llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), name.as_ptr().cast(), name.len(), - size.bits(), - align.bits() as u32, + cx.size_of(t).bits(), encoding, ) }; @@ -2187,9 +2182,6 @@ fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&' name.as_ptr().cast(), name.len(), actual_type_metadata, - unknown_file_metadata(cx), - 0, - 0, )) }) } else { diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 8c9a2c09c272c..8c580847ef8fd 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -252,7 +252,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let function_type_metadata = unsafe { let fn_signature = get_function_signature(self, fn_abi); - llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), file_metadata, fn_signature) + llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature) }; // Find the enclosing function, in case this is a closure. @@ -265,8 +265,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // name if necessary. let generics = self.tcx().generics_of(enclosing_fn_def_id); let substs = instance.substs.truncate_to(self.tcx(), generics); - let template_parameters = - get_template_parameters(self, &generics, substs, file_metadata, &mut name); + let template_parameters = get_template_parameters(self, &generics, substs, &mut name); // Get the linkage_name, which is just the symbol name let linkage_name = mangled_name_of_instance(self, instance); @@ -388,7 +387,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { cx: &CodegenCx<'ll, 'tcx>, generics: &ty::Generics, substs: SubstsRef<'tcx>, - file_metadata: &'ll DIFile, name_to_append_suffix_to: &mut String, ) -> &'ll DIArray { if substs.types().next().is_none() { @@ -429,9 +427,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { name.as_ptr().cast(), name.len(), actual_type_metadata, - file_metadata, - 0, - 0, )) }) } else { diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 9cb0f0e0c2e67..3fb7ff3cb8dfd 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1655,7 +1655,6 @@ extern "C" { pub fn LLVMRustDIBuilderCreateSubroutineType( Builder: &DIBuilder<'a>, - File: &'a DIFile, ParameterTypes: &'a DIArray, ) -> &'a DICompositeType; @@ -1682,7 +1681,6 @@ extern "C" { Name: *const c_char, NameLen: size_t, SizeInBits: u64, - AlignInBits: u32, Encoding: c_uint, ) -> &'a DIBasicType; @@ -1880,9 +1878,6 @@ extern "C" { Name: *const c_char, NameLen: size_t, Ty: &'a DIType, - File: &'a DIFile, - LineNo: c_uint, - ColumnNo: c_uint, ) -> &'a DITemplateTypeParameter; pub fn LLVMRustDIBuilderCreateNameSpace( @@ -1948,7 +1943,6 @@ extern "C" { Reloc: RelocModel, Level: CodeGenOptLevel, UseSoftFP: bool, - PositionIndependentExecutable: bool, FunctionSections: bool, DataSections: bool, TrapUnreachable: bool, diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 6c638c5453a18..02dcfb8e82952 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -445,7 +445,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( const char *TripleStr, const char *CPU, const char *Feature, const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc, LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat, - bool PositionIndependentExecutable, bool FunctionSections, + bool FunctionSections, bool DataSections, bool TrapUnreachable, bool Singlethread, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index b988d06871bf6..24f35627d10e5 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -720,7 +720,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef File, LLVMMetadataRef ParameterTypes) { return wrap(Builder->createSubroutineType( DITypeRefArray(unwrap(ParameterTypes)))); @@ -755,7 +754,7 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType( LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, - uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding) { + uint64_t SizeInBits, unsigned Encoding) { return wrap(Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding)); } @@ -964,9 +963,7 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, size_t NameLen, - LLVMMetadataRef Ty, LLVMMetadataRef File, unsigned LineNo, - unsigned ColumnNo) { + const char *Name, size_t NameLen, LLVMMetadataRef Ty) { return wrap(Builder->createTemplateTypeParameter( unwrapDI(Scope), StringRef(Name, NameLen), unwrapDI(Ty))); } From 93abdd75114dd16e1297370603754fd2ea1e0964 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 20 May 2020 12:15:43 -0300 Subject: [PATCH 134/695] Add some teams to prioritization exclude_labels --- triagebot.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 2210a8ff8e656..f12d516376322 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -37,5 +37,9 @@ label = "ICEBreaker-Cleanup-Crew" [prioritize] label = "I-prioritize" prioritize_on = ["regression-from-stable-to-stable", "regression-from-stable-to-beta", "regression-from-stable-to-nightly"] -priority_labels = "P-*" +exclude_labels = [ + "P-*", + "T-infra", + "T-release", +] zulip_stream = 227806 From 4a10f6cd084b4fb72485bff597dfbb5852042a33 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Thu, 21 May 2020 23:18:28 +0200 Subject: [PATCH 135/695] Enable ARM TME (Transactional Memory Extensions) --- src/librustc_codegen_llvm/llvm_util.rs | 1 + src/libstd/tests/run-time-detect.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 286d3630181cb..67a2251e8593e 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -170,6 +170,7 @@ const AARCH64_WHITELIST: &[(&str, Option)] = &[ ("fp16", Some(sym::aarch64_target_feature)), ("rcpc", Some(sym::aarch64_target_feature)), ("dotprod", Some(sym::aarch64_target_feature)), + ("tme", Some(sym::aarch64_target_feature)), ("v8.1a", Some(sym::aarch64_target_feature)), ("v8.2a", Some(sym::aarch64_target_feature)), ("v8.3a", Some(sym::aarch64_target_feature)), diff --git a/src/libstd/tests/run-time-detect.rs b/src/libstd/tests/run-time-detect.rs index 2e6d1bc8efd3f..8dd1a8ac0d2df 100644 --- a/src/libstd/tests/run-time-detect.rs +++ b/src/libstd/tests/run-time-detect.rs @@ -32,6 +32,7 @@ fn aarch64_linux() { println!("rdm: {}", is_aarch64_feature_detected!("rdm")); println!("rcpc: {}", is_aarch64_feature_detected!("rcpc")); println!("dotprod: {}", is_aarch64_feature_detected!("dotprod")); + println!("tme: {}", is_aarch64_feature_detected!("tme")); } #[test] From e9fed696b5ae033195e2ec2f9ba1edf2c3dae5c5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 21 May 2020 17:05:13 -0700 Subject: [PATCH 136/695] Impl Ord for proc_macro::LineColumn --- src/libproc_macro/lib.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f11401b5a0c7c..2d5bd7e872bd5 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -39,6 +39,7 @@ mod diagnostic; #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub use diagnostic::{Diagnostic, Level, MultiSpan}; +use std::cmp::Ordering; use std::ops::{Bound, RangeBounds}; use std::path::PathBuf; use std::str::FromStr; @@ -420,6 +421,20 @@ impl !Send for LineColumn {} #[unstable(feature = "proc_macro_span", issue = "54725")] impl !Sync for LineColumn {} +#[unstable(feature = "proc_macro_span", issue = "54725")] +impl Ord for LineColumn { + fn cmp(&self, other: &Self) -> Ordering { + self.line.cmp(&other.line).then(self.column.cmp(&other.column)) + } +} + +#[unstable(feature = "proc_macro_span", issue = "54725")] +impl PartialOrd for LineColumn { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + /// The source file of a given `Span`. #[unstable(feature = "proc_macro_span", issue = "54725")] #[derive(Clone)] From 5a4bf448c764696be75eafb6631e182d95064e72 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 21 May 2020 17:12:29 -0700 Subject: [PATCH 137/695] Add test for proc_macro::LineColumn --- src/libproc_macro/tests/test.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/libproc_macro/tests/test.rs diff --git a/src/libproc_macro/tests/test.rs b/src/libproc_macro/tests/test.rs new file mode 100644 index 0000000000000..331b330cf29f0 --- /dev/null +++ b/src/libproc_macro/tests/test.rs @@ -0,0 +1,12 @@ +#![feature(proc_macro_span)] + +use proc_macro::LineColumn; + +#[test] +fn test_line_column_ord() { + let line0_column0 = LineColumn { line: 0, column: 0 }; + let line0_column1 = LineColumn { line: 0, column: 1 }; + let line1_column0 = LineColumn { line: 1, column: 0 }; + assert!(line0_column0 < line0_column1); + assert!(line0_column1 < line1_column0); +} From 47cc221e9827ab1b92f20353f423916a3f14d182 Mon Sep 17 00:00:00 2001 From: csmoe Date: Fri, 22 May 2020 10:11:17 +0800 Subject: [PATCH 138/695] add mcve for issue 72442 --- src/test/ui/async-await/issue-72442.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/test/ui/async-await/issue-72442.rs diff --git a/src/test/ui/async-await/issue-72442.rs b/src/test/ui/async-await/issue-72442.rs new file mode 100644 index 0000000000000..cced1da48f693 --- /dev/null +++ b/src/test/ui/async-await/issue-72442.rs @@ -0,0 +1,25 @@ +// edition:2018 + +use std::fs::File; +use std::future::Future; +use std::io::prelude::*; + +fn main() -> Result<(), Box> { + block_on(async { + { + let path = std::path::Path::new("."); + let mut f = File::open(path.to_str())?; + //~^ ERROR the trait bound `std::option::Option<&str>: std::convert::AsRef` is not satisfied + let mut src = String::new(); + f.read_to_string(&mut src)?; + Ok(()) + } + }) +} + +fn block_on(f: F) -> F::Output +where + F: Future>>, +{ + Ok(()) +} From 7cdc8972342e8f4946b518ac4886079f604cf2c1 Mon Sep 17 00:00:00 2001 From: csmoe Date: Fri, 22 May 2020 10:11:52 +0800 Subject: [PATCH 139/695] only try to suggest for try trait_ref --- src/libcore/ops/try.rs | 1 + src/librustc_hir/lang_items.rs | 2 ++ src/librustc_trait_selection/traits/error_reporting/mod.rs | 6 +++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 996a01d413cbc..e15ea11569f34 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -25,6 +25,7 @@ ) )] #[doc(alias = "?")] +#[cfg_attr(not(bootstrap), lang = "try")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 53f72804a848d..8921cc0c99dca 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -256,4 +256,6 @@ language_item_table! { AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; TerminationTraitLangItem, "termination", termination, Target::Trait; + + TryTraitLangItem, "try", try_trait, Target::Trait; } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 139b860072224..f18a417cccd05 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -402,7 +402,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); self.note_version_mismatch(&mut err, &trait_ref); - self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); + + if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() { + self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); + } + if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { err.emit(); return; From d24ba6d1243db648eac365eaf637264e6d04d5f1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 21 May 2020 19:27:12 -0700 Subject: [PATCH 140/695] Perform MIR NRVO even if types don't match --- src/librustc_mir/transform/nrvo.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/transform/nrvo.rs b/src/librustc_mir/transform/nrvo.rs index 941ffa94aa857..ffad1ebea005b 100644 --- a/src/librustc_mir/transform/nrvo.rs +++ b/src/librustc_mir/transform/nrvo.rs @@ -44,18 +44,6 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { } }; - // Sometimes, the return place is assigned a local of a different but coercable type, for - // example `&T` instead of `&mut T`. Overwriting the `LocalInfo` for the return place would - // result in it having an incorrect type. Although this doesn't seem to cause a problem in - // codegen, bail out anyways since it happens so rarely. - let ret_ty = body.local_decls[mir::RETURN_PLACE].ty; - let assigned_ty = body.local_decls[returned_local].ty; - if ret_ty != assigned_ty { - debug!("`{:?}` was eligible for NRVO but for type mismatch", src.def_id()); - debug!("typeof(_0) != typeof({:?}); {:?} != {:?}", returned_local, ret_ty, assigned_ty); - return; - } - debug!( "`{:?}` was eligible for NRVO, making {:?} the return place", src.def_id(), @@ -72,6 +60,12 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { // Overwrite the debuginfo of `_0` with that of the renamed local. let (renamed_decl, ret_decl) = body.local_decls.pick2_mut(returned_local, mir::RETURN_PLACE); + + // Sometimes, the return place is assigned a local of a different but coercable type, for + // example `&mut T` instead of `&T`. Overwriting the `LocalInfo` for the return place means + // its type may no longer match the return type of its function. This doesn't cause a + // problem in codegen because these two types are layout-compatible, but may be unexpected. + debug!("_0: {:?} = {:?}: {:?}", ret_decl.ty, returned_local, renamed_decl.ty); ret_decl.clone_from(renamed_decl); // The return place is always mutable. From 526dbd3d9718bf55a4d900bb68a9abff2be7019a Mon Sep 17 00:00:00 2001 From: Nathan West Date: Thu, 21 May 2020 23:45:43 -0400 Subject: [PATCH 141/695] Clarified the documentation for Formatter::precision --- src/libcore/fmt/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 95411b525d0db..7a8db024d4a74 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1611,7 +1611,8 @@ impl<'a> Formatter<'a> { self.width } - /// Optionally specified precision for numeric types. + /// Optionally specified precision for numeric types. Alternatively, the + /// maximum width for string types. /// /// # Examples /// From 6a3aae8aea2448432d4fd0f7c3a22778beaab831 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 21 May 2020 19:48:44 -0700 Subject: [PATCH 142/695] Add flag to open docs: x.py doc --open Tested with: # opens doc/index.html x.py doc --stage 0 --open x.py doc --stage 0 --open src/doc # opens doc/book/index.html x.py doc --stage 0 --open src/doc/book # opens doc/std/index.html x.py doc --stage 0 --open src/libstd # opens doc/proc_macro/index.html x.py doc --stage 0 --open src/libproc_macro # opens both x.py doc --stage 0 --open src/libstd src/libproc_macro --- Cargo.lock | 1 + src/bootstrap/Cargo.toml | 1 + src/bootstrap/builder.rs | 2 +- src/bootstrap/doc.rs | 59 +++++++++++++++++++++++++++++++++++++++- src/bootstrap/flags.rs | 14 +++++++++- 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d81fd6e8d3afd..b0b9e2c27df9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,6 +213,7 @@ dependencies = [ "lazy_static 1.4.0", "libc", "num_cpus", + "opener", "pretty_assertions", "serde", "serde_json", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index f7856f6a7fcb1..c4918d7f2e714 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -48,6 +48,7 @@ toml = "0.5" lazy_static = "1.3.0" time = "0.1" ignore = "0.4.10" +opener = "0.4" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 4bc81a7b42dc0..5489b1bc66b64 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -503,7 +503,7 @@ impl<'a> Builder<'a> { Subcommand::Check { ref paths } => (Kind::Check, &paths[..]), Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]), Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]), - Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), + Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]), Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]), Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]), Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]), diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 7eab92ddc92a9..be5e3bfee303f 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -70,6 +70,35 @@ book!( RustdocBook, "src/doc/rustdoc", "rustdoc"; ); +fn open(builder: &Builder<'_>, path: impl AsRef) { + if builder.config.dry_run || !builder.config.cmd.open() { + return; + } + + let path = path.as_ref(); + builder.info(&format!("Opening doc {}", path.to_string_lossy())); + + // ignore error + let _ = opener::open(path); +} + +// "src/libstd" -> ["src", "libstd"] +// +// Used for deciding whether a particular step is one requested by the user on +// the `x.py doc` command line, which determines whether `--open` will open that +// page. +fn components_simplified(path: &PathBuf) -> Vec<&str> { + path.iter().map(|component| component.to_str().unwrap_or("???")).collect() +} + +fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool { + builder + .paths + .iter() + .map(components_simplified) + .any(|requested| requested.iter().copied().eq(path.split("/"))) +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: Interned, @@ -200,6 +229,12 @@ impl Step for TheBook { invoke_rustdoc(builder, compiler, target, path); } + + if is_explicit_request(builder, "src/doc/book") { + let out = builder.doc_out(target); + let index = out.join("book").join("index.html"); + open(builder, &index); + } } } @@ -338,6 +373,13 @@ impl Step for Standalone { } builder.run(&mut cmd); } + + // We open doc/index.html as the default if invoked as `x.py doc --open` + // with no particular explicit doc requested (e.g. src/libcore). + if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") { + let index = out.join("index.html"); + open(builder, &index); + } } } @@ -418,10 +460,25 @@ impl Step for Std { builder.run(&mut cargo.into()); }; - for krate in &["alloc", "core", "std", "proc_macro", "test"] { + let krates = ["alloc", "core", "std", "proc_macro", "test"]; + for krate in &krates { run_cargo_rustdoc_for(krate); } builder.cp_r(&my_out, &out); + + // Look for src/libstd, src/libcore etc in the `x.py doc` arguments and + // open the corresponding rendered docs. + for path in builder.paths.iter().map(components_simplified) { + if path.get(0) == Some(&"src") + && path.get(1).map_or(false, |dir| dir.starts_with("lib")) + { + let requested_crate = &path[1][3..]; + if krates.contains(&requested_crate) { + let index = out.join(requested_crate).join("index.html"); + open(builder, &index); + } + } + } } } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 646b9e05d99c3..cfaa43f397095 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -61,6 +61,7 @@ pub enum Subcommand { }, Doc { paths: Vec, + open: bool, }, Test { paths: Vec, @@ -248,6 +249,9 @@ To learn more about a subcommand, run `./x.py -h`", "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); } + "doc" => { + opts.optflag("", "open", "open the docs in a browser"); + } "clean" => { opts.optflag("", "all", "clean all build artifacts"); } @@ -404,6 +408,7 @@ Arguments: ./x.py doc src/doc/book ./x.py doc src/doc/nomicon ./x.py doc src/doc/book src/libstd + ./x.py doc src/libstd --open If no arguments are passed then everything is documented: @@ -479,7 +484,7 @@ Arguments: }, }, "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") }, - "doc" => Subcommand::Doc { paths }, + "doc" => Subcommand::Doc { paths, open: matches.opt_present("open") }, "clean" => { if !paths.is_empty() { println!("\nclean does not take a path argument\n"); @@ -613,6 +618,13 @@ impl Subcommand { _ => None, } } + + pub fn open(&self) -> bool { + match *self { + Subcommand::Doc { open, .. } => open, + _ => false, + } + } } fn split(s: &[String]) -> Vec { From 407958a2b88d1028e2a86f5927091540f6be04c4 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Sun, 17 May 2020 16:49:18 +0800 Subject: [PATCH 143/695] Replace obligation construction with deref_steps() --- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/demand.rs | 72 ++++++++++----------------- 2 files changed, 27 insertions(+), 47 deletions(-) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 2a1c6b895ce20..a324bd03eca8f 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -887,7 +887,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerce = Coerce::new(self, cause, AllowTwoPhase::No); coerce .autoderef(rustc_span::DUMMY_SP, expr_ty) - .find_map(|(ty, steps)| coerce.unify(ty, target).ok().map(|_| steps)) + .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps)) } /// Given some expressions, their known unified type and another expression, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index fc7a9c1d59b76..700b9359d06ed 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -1,16 +1,15 @@ use crate::check::FnCtxt; use rustc_infer::infer::InferOk; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCause}; +use rustc_trait_selection::traits::ObligationCause; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::lang_items::{CloneTraitLangItem, DerefTraitLangItem}; +use rustc_hir::lang_items::CloneTraitLangItem; use rustc_hir::{is_range_literal, Node}; use rustc_middle::ty::adjustment::AllowTwoPhase; -use rustc_middle::ty::{self, AssocItem, ToPredicate, Ty, TypeAndMut}; +use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -633,48 +632,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } _ if sp == expr.span && !is_macro => { - // Check for `Deref` implementations by constructing a predicate to - // prove: `::Output == U` - let deref_trait = self.tcx.require_lang_item(DerefTraitLangItem, Some(sp)); - let item_def_id = self - .tcx - .associated_items(deref_trait) - .in_definition_order() - .find(|item| item.kind == ty::AssocKind::Type) - .unwrap() - .def_id; - let predicate = - ty::PredicateKind::Projection(ty::Binder::bind(ty::ProjectionPredicate { - // `::Output` - projection_ty: ty::ProjectionTy { - // `T` - substs: self.tcx.intern_substs(&[checked_ty.into()]), - // `Deref::Output` - item_def_id, - }, - // `U` - ty: expected, - })) - .to_predicate(self.tcx); - let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); - let impls_deref = self.infcx.predicate_may_hold(&obligation); - - // For a suggestion to make sense, the type would need to be `Copy`. - let is_copy = self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp); - - if is_copy && impls_deref { - if let Ok(code) = sm.span_to_snippet(sp) { - let message = if checked_ty.is_region_ptr() { - "consider dereferencing the borrow" - } else { - "consider dereferencing the type" - }; - let suggestion = if is_struct_pat_shorthand_field { - format!("{}: *{}", code, code) - } else { - format!("*{}", code) - }; - return Some((sp, message, suggestion, Applicability::MachineApplicable)); + if let Some(steps) = self.deref_steps(checked_ty, expected) { + if steps == 1 { + // For a suggestion to make sense, the type would need to be `Copy`. + if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp) { + if let Ok(code) = sm.span_to_snippet(sp) { + let message = if checked_ty.is_region_ptr() { + "consider dereferencing the borrow" + } else { + "consider dereferencing the type" + }; + let suggestion = if is_struct_pat_shorthand_field { + format!("{}: *{}", code, code) + } else { + format!("*{}", code) + }; + return Some(( + sp, + message, + suggestion, + Applicability::MachineApplicable, + )); + } + } } } } From 52bb09abba48f1e68421c8fe18b30cee011c84ad Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 May 2020 16:54:20 -0400 Subject: [PATCH 144/695] Rewrite `Parser::collect_tokens` The previous implementation did not work when called on an opening delimiter, or when called re-entrantly from the same `TokenCursor` stack depth. --- src/librustc_parse/parser/mod.rs | 186 +++++++++++------- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- 3 files changed, 115 insertions(+), 75 deletions(-) diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index bdb4d7c9df6be..b21524cb9bdd2 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -118,6 +118,8 @@ impl<'a> Drop for Parser<'a> { struct TokenCursor { frame: TokenCursorFrame, stack: Vec, + cur_token: Option, + collecting: Option, } #[derive(Clone)] @@ -127,30 +129,24 @@ struct TokenCursorFrame { open_delim: bool, tree_cursor: tokenstream::Cursor, close_delim: bool, - last_token: LastToken, } -/// This is used in `TokenCursorFrame` above to track tokens that are consumed -/// by the parser, and then that's transitively used to record the tokens that -/// each parse AST item is created with. -/// -/// Right now this has two states, either collecting tokens or not collecting -/// tokens. If we're collecting tokens we just save everything off into a local -/// `Vec`. This should eventually though likely save tokens from the original -/// token stream and just use slicing of token streams to avoid creation of a -/// whole new vector. -/// -/// The second state is where we're passively not recording tokens, but the last -/// token is still tracked for when we want to start recording tokens. This -/// "last token" means that when we start recording tokens we'll want to ensure -/// that this, the first token, is included in the output. -/// -/// You can find some more example usage of this in the `collect_tokens` method -/// on the parser. -#[derive(Clone)] -enum LastToken { - Collecting(Vec), - Was(Option), +/// Used to track additional state needed by `collect_tokens` +#[derive(Clone, Debug)] +struct Collecting { + /// Holds the current tokens captured during the most + /// recent call to `collect_tokens` + buf: Vec, + /// The depth of the `TokenCursor` stack at the time + /// collection was started. When we encounter a `TokenTree::Delimited`, + /// we want to record the `TokenTree::Delimited` itself, + /// but *not* any of the inner tokens while we are inside + /// the new frame (this would cause us to record duplicate tokens). + /// + /// This `depth` fields tracks stack depth we are recording tokens. + /// Only tokens encountered at this depth will be recorded. See + /// `TokenCursor::next` for more details. + depth: usize, } impl TokenCursorFrame { @@ -161,7 +157,6 @@ impl TokenCursorFrame { open_delim: delim == token::NoDelim, tree_cursor: tts.clone().into_trees(), close_delim: delim == token::NoDelim, - last_token: LastToken::Was(None), } } } @@ -171,12 +166,12 @@ impl TokenCursor { loop { let tree = if !self.frame.open_delim { self.frame.open_delim = true; - TokenTree::open_tt(self.frame.span, self.frame.delim) - } else if let Some(tree) = self.frame.tree_cursor.next() { + TokenTree::open_tt(self.frame.span, self.frame.delim).into() + } else if let Some(tree) = self.frame.tree_cursor.next_with_joint() { tree } else if !self.frame.close_delim { self.frame.close_delim = true; - TokenTree::close_tt(self.frame.span, self.frame.delim) + TokenTree::close_tt(self.frame.span, self.frame.delim).into() } else if let Some(frame) = self.stack.pop() { self.frame = frame; continue; @@ -184,12 +179,25 @@ impl TokenCursor { return Token::new(token::Eof, DUMMY_SP); }; - match self.frame.last_token { - LastToken::Collecting(ref mut v) => v.push(tree.clone().into()), - LastToken::Was(ref mut t) => *t = Some(tree.clone().into()), + // Don't set an open delimiter as our current token - we want + // to leave it as the full `TokenTree::Delimited` from the previous + // iteration of this loop + if !matches!(tree.0, TokenTree::Token(Token { kind: TokenKind::OpenDelim(_), .. })) { + self.cur_token = Some(tree.clone()); + } + + if let Some(collecting) = &mut self.collecting { + if collecting.depth == self.stack.len() { + debug!( + "TokenCursor::next(): collected {:?} at depth {:?}", + tree, + self.stack.len() + ); + collecting.buf.push(tree.clone().into()) + } } - match tree { + match tree.0 { TokenTree::Token(token) => return token, TokenTree::Delimited(sp, delim, tts) => { let frame = TokenCursorFrame::new(sp, delim, &tts); @@ -350,6 +358,8 @@ impl<'a> Parser<'a> { token_cursor: TokenCursor { frame: TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, &tokens), stack: Vec::new(), + cur_token: None, + collecting: None, }, desugar_doc_comments, unmatched_angle_bracket_count: 0, @@ -1105,65 +1115,95 @@ impl<'a> Parser<'a> { } } + /// Records all tokens consumed by the provided callback, + /// including the current token. These tokens are collected + /// into a `TokenStream`, and returned along with the result + /// of the callback. + /// + /// Note: If your callback consumes an opening delimiter + /// (including the case where you call `collect_tokens` + /// when the current token is an opening delimeter), + /// you must also consume the corresponding closing delimiter. + /// + /// That is, you can consume + /// `something ([{ }])` or `([{}])`, but not `([{}]` + /// + /// This restriction shouldn't be an issue in practice, + /// since this function is used to record the tokens for + /// a parsed AST item, which always has matching delimiters. fn collect_tokens( &mut self, f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, (R, TokenStream)> { // Record all tokens we parse when parsing this item. - let mut tokens = Vec::new(); - let prev_collecting = match self.token_cursor.frame.last_token { - LastToken::Collecting(ref mut list) => Some(mem::take(list)), - LastToken::Was(ref mut last) => { - tokens.extend(last.take()); - None - } - }; - self.token_cursor.frame.last_token = LastToken::Collecting(tokens); - let prev = self.token_cursor.stack.len(); + let tokens: Vec = self.token_cursor.cur_token.clone().into_iter().collect(); + debug!("collect_tokens: starting with {:?}", tokens); + + // We need special handling for the case where `collect_tokens` is called + // on an opening delimeter (e.g. '('). At this point, we have already pushed + // a new frame - however, we want to record the original `TokenTree::Delimited`, + // for consistency with the case where we start recording one token earlier. + // See `TokenCursor::next` to see how `cur_token` is set up. + let prev_depth = + if matches!(self.token_cursor.cur_token, Some((TokenTree::Delimited(..), _))) { + if self.token_cursor.stack.is_empty() { + // There is nothing below us in the stack that + // the function could consume, so the only thing it can legally + // capture is the entire contents of the current frame. + return Ok((f(self)?, TokenStream::new(tokens))); + } + // We have already recorded the full `TokenTree::Delimited` when we created + // our `tokens` vector at the start of this function. We are now inside + // a new frame corresponding to the `TokenTree::Delimited` we already recoreded. + // We don't want to record any of the tokens inside this frame, since they + // will be duplicates of the tokens nested inside the `TokenTree::Delimited`. + // Therefore, we set our recording depth to the *previous* frame. This allows + // us to record a sequence like: `(foo).bar()`: the `(foo)` will be recored + // as our initial `cur_token`, while the `.bar()` will be recored after we + // pop the `(foo)` frame. + self.token_cursor.stack.len() - 1 + } else { + self.token_cursor.stack.len() + }; + let prev_collecting = + self.token_cursor.collecting.replace(Collecting { buf: tokens, depth: prev_depth }); + let ret = f(self); - let last_token = if self.token_cursor.stack.len() == prev { - &mut self.token_cursor.frame.last_token - } else if self.token_cursor.stack.get(prev).is_none() { - // This can happen due to a bad interaction of two unrelated recovery mechanisms with - // mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(` - // (#62881). - return Ok((ret?, TokenStream::default())); + + let mut collected_tokens = if let Some(collecting) = self.token_cursor.collecting.take() { + collecting.buf } else { - &mut self.token_cursor.stack[prev].last_token + let msg = format!("our vector went away?"); + debug!("collect_tokens: {}", msg); + self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg); + // This can happen due to a bad interaction of two unrelated recovery mechanisms + // with mismatched delimiters *and* recovery lookahead on the likely typo + // `pub ident(` (#62895, different but similar to the case above). + return Ok((ret?, TokenStream::default())); }; - // Pull out the tokens that we've collected from the call to `f` above. - let mut collected_tokens = match *last_token { - LastToken::Collecting(ref mut v) => mem::take(v), - LastToken::Was(ref was) => { - let msg = format!("our vector went away? - found Was({:?})", was); - debug!("collect_tokens: {}", msg); - self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg); - // This can happen due to a bad interaction of two unrelated recovery mechanisms - // with mismatched delimiters *and* recovery lookahead on the likely typo - // `pub ident(` (#62895, different but similar to the case above). - return Ok((ret?, TokenStream::default())); - } - }; + debug!("collect_tokens: got raw tokens {:?}", collected_tokens); // If we're not at EOF our current token wasn't actually consumed by // `f`, but it'll still be in our list that we pulled out. In that case // put it back. let extra_token = if self.token != token::Eof { collected_tokens.pop() } else { None }; - // If we were previously collecting tokens, then this was a recursive - // call. In that case we need to record all the tokens we collected in - // our parent list as well. To do that we push a clone of our stream - // onto the previous list. - match prev_collecting { - Some(mut list) => { - list.extend(collected_tokens.iter().cloned()); - list.extend(extra_token); - *last_token = LastToken::Collecting(list); - } - None => { - *last_token = LastToken::Was(extra_token); + if let Some(mut collecting) = prev_collecting { + // If we were previously collecting at the same depth, + // then the previous call to `collect_tokens` needs to see + // the tokens we just recorded. + // + // If we were previously recording at an lower `depth`, + // then the previous `collect_tokens` call already recorded + // this entire frame in the form of a `TokenTree::Delimited`, + // so there is nothing else for us to do. + if collecting.depth == prev_depth { + collecting.buf.extend(collected_tokens.iter().cloned()); + collecting.buf.extend(extra_token); + debug!("collect_tokens: updating previous buf to {:?}", collecting); } + self.token_cursor.collecting = Some(collecting) } Ok((ret?, TokenStream::new(collected_tokens))) diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index 1a07968bdf162..f60b6a00be129 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 0b3704e8e0045..42e7e78998063 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} From 16ba3e129d5d37c63b7000fcd4b52261e7f1c4f1 Mon Sep 17 00:00:00 2001 From: csmoe Date: Fri, 22 May 2020 10:12:03 +0800 Subject: [PATCH 145/695] bless issue-72442 --- src/test/ui/async-await/issue-72442.rs | 3 ++- src/test/ui/async-await/issue-72442.stderr | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/async-await/issue-72442.stderr diff --git a/src/test/ui/async-await/issue-72442.rs b/src/test/ui/async-await/issue-72442.rs index cced1da48f693..61c8c8c1594d3 100644 --- a/src/test/ui/async-await/issue-72442.rs +++ b/src/test/ui/async-await/issue-72442.rs @@ -1,4 +1,5 @@ // edition:2018 +// compile-flags:-Cincremental=tmp/issue-72442 use std::fs::File; use std::future::Future; @@ -9,7 +10,7 @@ fn main() -> Result<(), Box> { { let path = std::path::Path::new("."); let mut f = File::open(path.to_str())?; - //~^ ERROR the trait bound `std::option::Option<&str>: std::convert::AsRef` is not satisfied + //~^ ERROR the trait bound let mut src = String::new(); f.read_to_string(&mut src)?; Ok(()) diff --git a/src/test/ui/async-await/issue-72442.stderr b/src/test/ui/async-await/issue-72442.stderr new file mode 100644 index 0000000000000..5685433357871 --- /dev/null +++ b/src/test/ui/async-await/issue-72442.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `std::option::Option<&str>: std::convert::AsRef` is not satisfied + --> $DIR/issue-72442.rs:12:36 + | +LL | let mut f = File::open(path.to_str())?; + | ^^^^^^^^^^^^^ the trait `std::convert::AsRef` is not implemented for `std::option::Option<&str>` + | + ::: $SRC_DIR/libstd/fs.rs:LL:COL + | +LL | pub fn open>(path: P) -> io::Result { + | ----------- required by this bound in `std::fs::File::open` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From e776121431dc73b6e1782d5ddcc4e8d6d714f8e4 Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Fri, 22 May 2020 10:52:06 +0200 Subject: [PATCH 146/695] Using `!span.from_expansion()` instead of snippets --- .../traits/error_reporting/suggestions.rs | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index c90769c66556d..24ca5ade59719 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -571,30 +571,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Because of this, we modify the error to refer to the original obligation and // return early in the caller. - let has_colon = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|w| w.contains(":")) - .unwrap_or(false); - - let has_double_colon = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|w| w.contains("::")) - .unwrap_or(false); - - let has_bracket = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|w| w.contains("{")) - .unwrap_or(false); - let msg = format!( "the trait bound `{}: {}` is not satisfied", found, @@ -619,7 +595,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); // This if is to prevent a special edge-case - if !has_colon || has_double_colon || has_bracket { + if !span.from_expansion() { // We don't want a borrowing suggestion on the fields in structs, // ``` // struct Foo { From 9ff502029d379bebc50cf92a97f019fefba09d79 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Fri, 22 May 2020 10:07:46 +0200 Subject: [PATCH 147/695] Add core::future::IntoFuture This patch adds `core::future::IntoFuture`. However unlike earlier PRs this patch does not integrate it into the `async/.await` lowering. That integration should be done in a follow-up PR. --- src/libcore/future/into_future.rs | 27 +++++++++++++++++++++++++++ src/libcore/future/mod.rs | 4 ++++ src/libstd/future.rs | 14 +++++++++++++- src/libstd/lib.rs | 3 +++ 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/libcore/future/into_future.rs diff --git a/src/libcore/future/into_future.rs b/src/libcore/future/into_future.rs new file mode 100644 index 0000000000000..4020c254446e3 --- /dev/null +++ b/src/libcore/future/into_future.rs @@ -0,0 +1,27 @@ +use crate::future::Future; + +/// Conversion into a `Future`. +#[unstable(feature = "into_future", issue = "67644")] +pub trait IntoFuture { + /// The output that the future will produce on completion. + #[unstable(feature = "into_future", issue = "67644")] + type Output; + + /// Which kind of future are we turning this into? + #[unstable(feature = "into_future", issue = "67644")] + type Future: Future; + + /// Creates a future from a value. + #[unstable(feature = "into_future", issue = "67644")] + fn into_future(self) -> Self::Future; +} + +#[unstable(feature = "into_future", issue = "67644")] +impl IntoFuture for F { + type Output = F::Output; + type Future = F; + + fn into_future(self) -> Self::Future { + self + } +} diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index b5a102916a07e..6f6009b47e672 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -10,12 +10,16 @@ use crate::{ }; mod future; +mod into_future; mod pending; mod ready; #[stable(feature = "futures_api", since = "1.36.0")] pub use self::future::Future; +#[unstable(feature = "into_future", issue = "67644")] +pub use into_future::IntoFuture; + #[unstable(feature = "future_readiness_fns", issue = "70921")] pub use pending::{pending, Pending}; #[unstable(feature = "future_readiness_fns", issue = "70921")] diff --git a/src/libstd/future.rs b/src/libstd/future.rs index e2092cfefa369..89dd9fb9b2cd5 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -2,4 +2,16 @@ #[doc(inline)] #[stable(feature = "futures_api", since = "1.36.0")] -pub use core::future::*; +pub use core::future::Future; + +#[doc(inline)] +#[unstable(feature = "gen_future", issue = "50547")] +pub use core::future::{from_generator, get_context, ResumeTy}; + +#[doc(inline)] +#[unstable(feature = "future_readiness_fns", issue = "70921")] +pub use core::future::{pending, ready, Pending, Ready}; + +#[doc(inline)] +#[unstable(feature = "into_future", issue = "67644")] +pub use core::future::IntoFuture; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ac07af5e278fb..cc3e613fa3d60 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -266,12 +266,15 @@ #![feature(external_doc)] #![feature(fn_traits)] #![feature(format_args_nl)] +#![feature(future_readiness_fns)] +#![feature(gen_future)] #![feature(generator_trait)] #![feature(global_asm)] #![feature(hash_raw_entry)] #![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(int_error_matching)] +#![feature(into_future)] #![feature(integer_atomics)] #![feature(lang_items)] #![feature(libc)] From 6e5cb37b668db4d5ae1a8b01830bd0a88ac6a406 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 22 May 2020 13:24:34 +0200 Subject: [PATCH 148/695] Clean up E0600 explanation --- src/librustc_error_codes/error_codes/E0600.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0600.md b/src/librustc_error_codes/error_codes/E0600.md index 172e2a346c5a7..356006c72f3d1 100644 --- a/src/librustc_error_codes/error_codes/E0600.md +++ b/src/librustc_error_codes/error_codes/E0600.md @@ -1,6 +1,6 @@ An unary operator was used on a type which doesn't implement it. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0600 enum Question { From 985ebf2c4acce62e9dedf8ffb6ca95789add19e8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 15 May 2020 18:26:20 +0200 Subject: [PATCH 149/695] Clean up E0590 explanation --- src/librustc_error_codes/error_codes/E0590.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0590.md b/src/librustc_error_codes/error_codes/E0590.md index df7aa4f0a1e8d..11005b8336fca 100644 --- a/src/librustc_error_codes/error_codes/E0590.md +++ b/src/librustc_error_codes/error_codes/E0590.md @@ -1,13 +1,17 @@ -`break` or `continue` must include a label when used in the condition of a -`while` loop. +`break` or `continue` keywords were used in a condition of a `while` loop +without a label. -Example of erroneous code: +Erroneous code code: ```compile_fail,E0590 while break {} ``` +`break` or `continue` must include a label when used in the condition of a +`while` loop. + To fix this, add a label specifying which loop is being broken out of: + ``` 'foo: while break 'foo {} ``` From fc0675bf7508e4b2bb48ccf01ad2ecbd924d7b3b Mon Sep 17 00:00:00 2001 From: Tymoteusz Jankowski Date: Fri, 22 May 2020 11:50:22 +0200 Subject: [PATCH 150/695] Allow using `Self::` in doc --- .../passes/collect_intra_doc_links.rs | 54 +++++++++++- src/test/rustdoc/intra-link-self.rs | 88 +++++++++++++++++++ 2 files changed, 138 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 05f3b598ecdf4..adb7fc3eb9cff 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -431,6 +431,43 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { look_for_tests(&cx, &dox, &item, true); + // find item's parent to resolve `Self` in item's docs below + let parent_name = self.cx.as_local_hir_id(item.def_id).and_then(|item_hir| { + let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir); + let item_parent = self.cx.tcx.hir().find(parent_hir); + match item_parent { + Some(hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Impl { + self_ty: + hir::Ty { + kind: + hir::TyKind::Path(hir::QPath::Resolved( + _, + hir::Path { segments, .. }, + )), + .. + }, + .. + }, + .. + })) => segments.first().and_then(|seg| Some(seg.ident.to_string())), + Some(hir::Node::Item(hir::Item { + ident, kind: hir::ItemKind::Enum(..), .. + })) + | Some(hir::Node::Item(hir::Item { + ident, kind: hir::ItemKind::Struct(..), .. + })) + | Some(hir::Node::Item(hir::Item { + ident, kind: hir::ItemKind::Union(..), .. + })) + | Some(hir::Node::Item(hir::Item { + ident, kind: hir::ItemKind::Trait(..), .. + })) => Some(ident.to_string()), + _ => None, + } + }); + for (ori_link, link_range) in markdown_links(&dox) { // Bail early for real links. if ori_link.contains('/') { @@ -467,7 +504,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }; let (res, fragment) = { let mut kind = None; - let path_str = if let Some(prefix) = + let mut path_str = if let Some(prefix) = ["struct@", "enum@", "type@", "trait@", "union@"] .iter() .find(|p| link.starts_with(**p)) @@ -521,6 +558,15 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let base_node = if item.is_mod() && item.attrs.inner_docs { None } else { parent_node }; + let resolved_self; + // replace `Self` with suitable item's parent name + if path_str.starts_with("Self::") { + if let Some(ref name) = parent_name { + resolved_self = format!("{}::{}", name, &path_str[6..]); + path_str = &resolved_self; + } + } + match kind { Some(ns @ ValueNS) => { match self.resolve( @@ -529,7 +575,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { ¤t_item, base_node, &extra_fragment, - None, + Some(&item), ) { Ok(res) => res, Err(ErrorKind::ResolutionFailure) => { @@ -552,7 +598,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { ¤t_item, base_node, &extra_fragment, - None, + Some(&item), ) { Ok(res) => res, Err(ErrorKind::ResolutionFailure) => { @@ -577,7 +623,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { ¤t_item, base_node, &extra_fragment, - None, + Some(&item), ) { Err(ErrorKind::AnchorFailure(msg)) => { anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); diff --git a/src/test/rustdoc/intra-link-self.rs b/src/test/rustdoc/intra-link-self.rs index acf975f5c738e..97752d5cfcb5c 100644 --- a/src/test/rustdoc/intra-link-self.rs +++ b/src/test/rustdoc/intra-link-self.rs @@ -1,5 +1,7 @@ #![crate_name = "foo"] +// ignore-tidy-linelength + // @has foo/index.html '//a/@href' '../foo/struct.Foo.html#method.new' // @has foo/struct.Foo.html '//a/@href' '../foo/struct.Foo.html#method.new' @@ -27,3 +29,89 @@ impl Bar { unimplemented!() } } + +pub struct MyStruct { + // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#structfield.struct_field' + + /// [`struct_field`] + /// + /// [`struct_field`]: Self::struct_field + pub struct_field: u8, +} + +pub enum MyEnum { + // @has foo/enum.MyEnum.html '//a/@href' '../foo/enum.MyEnum.html#EnumVariant.v' + + /// [`EnumVariant`] + /// + /// [`EnumVariant`]: Self::EnumVariant + EnumVariant, +} + +pub union MyUnion { + // @has foo/union.MyUnion.html '//a/@href' '../foo/union.MyUnion.html#structfield.union_field' + + /// [`union_field`] + /// + /// [`union_field`]: Self::union_field + pub union_field: f32, +} + +pub trait MyTrait { + // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedtype.AssoType' + + /// [`AssoType`] + /// + /// [`AssoType`]: Self::AssoType + type AssoType; + + // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedconstant.ASSO_CONST' + + /// [`ASSO_CONST`] + /// + /// [`ASSO_CONST`]: Self::ASSO_CONST + const ASSO_CONST: i32 = 1; + + // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#method.asso_fn' + + /// [`asso_fn`] + /// + /// [`asso_fn`]: Self::asso_fn + fn asso_fn() {} +} + +impl MyStruct { + // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.for_impl' + + /// [`for_impl`] + /// + /// [`for_impl`]: Self::for_impl + pub fn for_impl() { + unimplemented!() + } +} + +impl MyTrait for MyStruct { + // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedtype.AssoType' + + /// [`AssoType`] + /// + /// [`AssoType`]: Self::AssoType + type AssoType = u32; + + // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedconstant.ASSO_CONST' + + /// [`ASSO_CONST`] + /// + /// [`ASSO_CONST`]: Self::ASSO_CONST + const ASSO_CONST: i32 = 10; + + // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.asso_fn' + + /// [`asso_fn`] + /// + /// [`asso_fn`]: Self::asso_fn + fn asso_fn() { + unimplemented!() + } +} From c00268d984b80e408f56b5d8180e2f1a80100c91 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 22 May 2020 02:40:39 +0200 Subject: [PATCH 151/695] Also install llvm-tools on toolchain setup --- setup-toolchain.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup-toolchain.sh b/setup-toolchain.sh index 6038ed697f91e..191ea4315a6b5 100755 --- a/setup-toolchain.sh +++ b/setup-toolchain.sh @@ -32,5 +32,5 @@ else TOOLCHAIN=() fi -rustup-toolchain-install-master -f -n master "${TOOLCHAIN[@]}" -c rustc-dev -- "$RUST_COMMIT" +rustup-toolchain-install-master -f -n master "${TOOLCHAIN[@]}" -c rustc-dev -c llvm-tools -- "$RUST_COMMIT" rustup override set master From 6b3cf63bf568cab4f8e05ea483ad97d5ea0e2eec Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 22 May 2020 14:45:51 +0200 Subject: [PATCH 152/695] Fix dogfood fallout --- clippy_lints/src/methods/mod.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 810a226b50d2a..32b3b7f7947f6 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1496,17 +1496,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { if let ty::Opaque(def_id, _) = ret_ty.kind { // one of the associated types must be Self for predicate in cx.tcx.predicates_of(def_id).predicates { - match predicate.0.kind() { - ty::PredicateKind::Projection(poly_projection_predicate) => { - let binder = poly_projection_predicate.ty(); - let associated_type = binder.skip_binder(); - - // walk the associated type and check for Self - if contains_self_ty(associated_type) { - return; - } - }, - _ => {}, + if let ty::PredicateKind::Projection(poly_projection_predicate) = predicate.0.kind() { + let binder = poly_projection_predicate.ty(); + let associated_type = binder.skip_binder(); + + // walk the associated type and check for Self + if contains_self_ty(associated_type) { + return; + } } } } From dc4b9fd863091d22396473b5d4e6cd5a048ee22b Mon Sep 17 00:00:00 2001 From: Elinvynia <59487684+Elinvynia@users.noreply.github.com> Date: Wed, 20 May 2020 22:14:47 +0200 Subject: [PATCH 153/695] Allow rust-highfive to label issues it creates. Replace sets with lists. --- src/tools/publish_toolstate.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 988a226706dc0..72437e070044c 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -39,6 +39,19 @@ 'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'}, } +LABELS = { + 'miri': ['A-miri', 'C-bug'], + 'rls': ['A-rls', 'C-bug'], + 'rustfmt': ['C-bug'], + 'book': ['C-bug'], + 'nomicon': ['C-bug'], + 'reference': ['C-bug'], + 'rust-by-example': ['C-bug'], + 'embedded-book': ['C-bug'], + 'edition-guide': ['C-bug'], + 'rustc-dev-guide': ['C-bug'], +} + REPOS = { 'miri': 'https://github.com/rust-lang/miri', 'rls': 'https://github.com/rust-lang/rls', @@ -132,6 +145,7 @@ def issue( assignees, relevant_pr_number, relevant_pr_user, + labels, ): # Open an issue about the toolstate failure. if status == 'test-fail': @@ -155,6 +169,7 @@ def issue( )), 'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number), 'assignees': list(assignees), + 'labels': labels, }) print("Creating issue:\n{}".format(request)) response = urllib2.urlopen(urllib2.Request( @@ -235,7 +250,7 @@ def update_latest( try: issue( tool, create_issue_for_status, MAINTAINERS.get(tool, ''), - relevant_pr_number, relevant_pr_user, + relevant_pr_number, relevant_pr_user, LABELS.get(tool, ''), ) except urllib2.HTTPError as e: # network errors will simply end up not creating an issue, but that's better From 2df69baa55fc762b43df9bbae2a867c3e3200a13 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 22 May 2020 15:29:47 +0000 Subject: [PATCH 154/695] Stabilize str_strip feature --- src/libcore/str/mod.rs | 7 ++----- src/librustc_trait_selection/lib.rs | 1 - src/tools/clippy/src/driver.rs | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index c517286d49898..b514e0f6d9cff 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -4052,15 +4052,13 @@ impl str { /// # Examples /// /// ``` - /// #![feature(str_strip)] - /// /// assert_eq!("foo:bar".strip_prefix("foo:"), Some("bar")); /// assert_eq!("foo:bar".strip_prefix("bar"), None); /// assert_eq!("foofoo".strip_prefix("foo"), Some("foo")); /// ``` #[must_use = "this returns the remaining substring as a new slice, \ without modifying the original"] - #[unstable(feature = "str_strip", reason = "newly added", issue = "67302")] + #[stable(feature = "str_strip", since = "1.45.0")] pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> { prefix.strip_prefix_of(self) } @@ -4082,14 +4080,13 @@ impl str { /// # Examples /// /// ``` - /// #![feature(str_strip)] /// assert_eq!("bar:foo".strip_suffix(":foo"), Some("bar")); /// assert_eq!("bar:foo".strip_suffix("bar"), None); /// assert_eq!("foofoo".strip_suffix("foo"), Some("foo")); /// ``` #[must_use = "this returns the remaining substring as a new slice, \ without modifying the original"] - #[unstable(feature = "str_strip", reason = "newly added", issue = "67302")] + #[stable(feature = "str_strip", since = "1.45.0")] pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str> where P: Pattern<'a>, diff --git a/src/librustc_trait_selection/lib.rs b/src/librustc_trait_selection/lib.rs index 4796b431d8dca..044239b047a4e 100644 --- a/src/librustc_trait_selection/lib.rs +++ b/src/librustc_trait_selection/lib.rs @@ -16,7 +16,6 @@ #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] -#![feature(str_strip)] #![feature(option_zip)] #![recursion_limit = "512"] // For rustdoc diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index d3a7e24937f95..3e1f423865b1d 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -1,6 +1,5 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(rustc_private)] -#![feature(str_strip)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) From 221c482142f84d5889edb8d17efab6470c81cf04 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 22 May 2020 15:29:47 +0000 Subject: [PATCH 155/695] Stabilize str_strip feature --- src/driver.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/driver.rs b/src/driver.rs index d3a7e24937f95..3e1f423865b1d 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,6 +1,5 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(rustc_private)] -#![feature(str_strip)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) From a578bed69ac2a9b33fcb871f9ad7dbf02355cb82 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 18 May 2020 18:35:49 -0400 Subject: [PATCH 156/695] new_without_default: do not suggest deriving --- clippy_lints/src/new_without_default.rs | 118 +++++------------------- tests/ui/new_without_default.rs | 11 +++ tests/ui/new_without_default.stderr | 35 ++++++- 3 files changed, 64 insertions(+), 100 deletions(-) diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index a599667b8d8a8..3b88e4c4cb194 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,27 +1,20 @@ use crate::utils::paths; use crate::utils::sugg::DiagnosticBuilderExt; -use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_hir_and_then}; +use crate::utils::{get_trait_def_id, return_ty, same_tys, span_lint_hir_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for types with a `fn new() -> Self` method and no /// implementation of /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html). /// - /// It detects both the case when a manual - /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) - /// implementation is required and also when it can be created with - /// `#[derive(Default)]` - /// /// **Why is this bad?** The user might expect to be able to use /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the /// type can be constructed without arguments. @@ -40,46 +33,17 @@ declare_clippy_lint! { /// } /// ``` /// - /// Instead, use: + /// To fix the lint, and a `Default` implementation that delegates to `new`: /// /// ```ignore /// struct Foo(Bar); /// /// impl Default for Foo { /// fn default() -> Self { - /// Foo(Bar::new()) + /// Foo::new() /// } /// } /// ``` - /// - /// Or, if - /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) - /// can be derived by `#[derive(Default)]`: - /// - /// ```rust - /// struct Foo; - /// - /// impl Foo { - /// fn new() -> Self { - /// Foo - /// } - /// } - /// ``` - /// - /// Instead, use: - /// - /// ```rust - /// #[derive(Default)] - /// struct Foo; - /// - /// impl Foo { - /// fn new() -> Self { - /// Foo - /// } - /// } - /// ``` - /// - /// You can also have `new()` call `Default::default()`. pub NEW_WITHOUT_DEFAULT, style, "`fn new() -> Self` method without `Default` implementation" @@ -158,46 +122,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { } } - if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) { - span_lint_hir_and_then( - cx, - NEW_WITHOUT_DEFAULT, - id, - impl_item.span, - &format!( - "you should consider deriving a `Default` implementation for `{}`", - self_ty - ), - |diag| { - diag.suggest_item_with_attr( - cx, - sp, - "try this", - "#[derive(Default)]", - Applicability::MaybeIncorrect, - ); - }); - } else { - span_lint_hir_and_then( - cx, - NEW_WITHOUT_DEFAULT, - id, - impl_item.span, - &format!( - "you should consider adding a `Default` implementation for `{}`", - self_ty - ), - |diag| { - diag.suggest_prepend_item( - cx, - item.span, - "try this", - &create_new_without_default_suggest_msg(self_ty), - Applicability::MaybeIncorrect, - ); - }, - ); - } + span_lint_hir_and_then( + cx, + NEW_WITHOUT_DEFAULT, + id, + impl_item.span, + &format!( + "you should consider adding a `Default` implementation for `{}`", + self_ty + ), + |diag| { + diag.suggest_prepend_item( + cx, + item.span, + "try this", + &create_new_without_default_suggest_msg(self_ty), + Applicability::MaybeIncorrect, + ); + }, + ); } } } @@ -217,18 +160,3 @@ fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String { }} }}", ty) } - -fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option { - match ty.kind { - ty::Adt(adt_def, substs) if adt_def.is_struct() => { - for field in adt_def.all_fields() { - let f_ty = field.ty(cx.tcx, substs); - if !implements_trait(cx, f_ty, default_trait_id, &[]) { - return None; - } - } - Some(cx.tcx.def_span(adt_def.did)) - }, - _ => None, - } -} diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index 781ea7bb15283..3b6041823d878 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -148,4 +148,15 @@ impl AllowDerive { } } +pub struct NewNotEqualToDerive { + foo: i32, +} + +impl NewNotEqualToDerive { + // This `new` implementation is not equal to a derived `Default`, so do not suggest deriving. + pub fn new() -> Self { + NewNotEqualToDerive { foo: 1 } + } +} + fn main() {} diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 5e485d40663f3..e529e441eb735 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -1,4 +1,4 @@ -error: you should consider deriving a `Default` implementation for `Foo` +error: you should consider adding a `Default` implementation for `Foo` --> $DIR/new_without_default.rs:8:5 | LL | / pub fn new() -> Foo { @@ -9,10 +9,14 @@ LL | | } = note: `-D clippy::new-without-default` implied by `-D warnings` help: try this | -LL | #[derive(Default)] +LL | impl Default for Foo { +LL | fn default() -> Self { +LL | Self::new() +LL | } +LL | } | -error: you should consider deriving a `Default` implementation for `Bar` +error: you should consider adding a `Default` implementation for `Bar` --> $DIR/new_without_default.rs:16:5 | LL | / pub fn new() -> Self { @@ -22,7 +26,11 @@ LL | | } | help: try this | -LL | #[derive(Default)] +LL | impl Default for Bar { +LL | fn default() -> Self { +LL | Self::new() +LL | } +LL | } | error: you should consider adding a `Default` implementation for `LtKo<'c>` @@ -42,5 +50,22 @@ LL | } LL | } | -error: aborting due to 3 previous errors +error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` + --> $DIR/new_without_default.rs:157:5 + | +LL | / pub fn new() -> Self { +LL | | NewNotEqualToDerive { foo: 1 } +LL | | } + | |_____^ + | +help: try this + | +LL | impl Default for NewNotEqualToDerive { +LL | fn default() -> Self { +LL | Self::new() +LL | } +LL | } + | + +error: aborting due to 4 previous errors From 01630b26ddcf647a6e87a0d6a18055a7c516cdbc Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 22 May 2020 18:30:26 +0200 Subject: [PATCH 157/695] Implement `Sync` for `process::Command on unix and vxworks --- src/libstd/process.rs | 6 +++--- src/libstd/sys/unix/process/process_common.rs | 6 ++++-- src/libstd/sys/vxworks/process/process_common.rs | 6 ++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index f7e7a5abf8ea6..4ba1940fd0ece 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -2105,8 +2105,8 @@ mod tests { } #[test] - fn test_command_implements_send() { - fn take_send_type(_: T) {} - take_send_type(Command::new("")) + fn test_command_implements_send_sync() { + fn take_send_sync_type(_: T) {} + take_send_sync_type(Command::new("")) } } diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 859da691ad278..2d7267263dedf 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -86,11 +86,13 @@ pub struct Command { stderr: Option, } -// Create a new type for argv, so that we can make it `Send` +// Create a new type for argv, so that we can make it `Send` and `Sync` struct Argv(Vec<*const c_char>); -// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args` +// It is safe to make `Argv` `Send` and `Sync`, because it contains +// pointers to memory owned by `Command.args` unsafe impl Send for Argv {} +unsafe impl Sync for Argv {} // passed back to std::process with the pipes connected to the child, if any // were requested diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs index 6d5506bec5f7d..78b6e9a4db785 100644 --- a/src/libstd/sys/vxworks/process/process_common.rs +++ b/src/libstd/sys/vxworks/process/process_common.rs @@ -49,11 +49,13 @@ pub struct Command { stderr: Option, } -// Create a new type for argv, so that we can make it `Send` +// Create a new type for `Argv`, so that we can make it `Send` and `Sync` struct Argv(Vec<*const c_char>); -// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args` +// It is safe to make `Argv` `Send` and `Sync`, because it contains +// pointers to memory owned by `Command.args` unsafe impl Send for Argv {} +unsafe impl Sync for Argv {} // passed back to std::process with the pipes connected to the child, if any // were requested From 33f90f213d4c5495bba988b9d81982d73553096e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 19 May 2020 20:09:59 +0100 Subject: [PATCH 158/695] Check for upper bound universe errors more carefully --- .../infer/lexical_region_resolve/mod.rs | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs index 33a80fb747101..5d64a987cbd0a 100644 --- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs @@ -49,7 +49,10 @@ pub fn resolve<'tcx>( let mut values = resolver.infer_variable_values(&mut errors); let re_erased = region_rels.tcx.lifetimes.re_erased; - values.values.iter_mut().for_each(|v| *v = VarValue::Value(re_erased)); + values.values.iter_mut().for_each(|v| match *v { + VarValue::Value(ref mut r) => *r = re_erased, + VarValue::ErrorValue => {} + }); (values, errors) } RegionckMode::Erase { suppress_errors: true } => { @@ -290,8 +293,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // Find all the "upper bounds" -- that is, each region `b` such that // `r0 <= b` must hold. - let (member_upper_bounds, _) = - self.collect_concrete_regions(graph, member_vid, OUTGOING, None); + let (member_upper_bounds, ..) = + self.collect_bounding_regions(graph, member_vid, OUTGOING, None); // Get an iterator over the *available choice* -- that is, // each choice region `c` where `lb <= c` and `c <= ub` for all the @@ -716,7 +719,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { graph: &RegionGraph<'tcx>, errors: &mut Vec>, ) { - debug!("collect_var_errors"); + debug!("collect_var_errors, var_data = {:#?}", var_data.values); // This is the best way that I have found to suppress // duplicate and related errors. Basically we keep a set of @@ -815,10 +818,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. - let (mut lower_bounds, lower_dup) = - self.collect_concrete_regions(graph, node_idx, INCOMING, Some(dup_vec)); - let (mut upper_bounds, upper_dup) = - self.collect_concrete_regions(graph, node_idx, OUTGOING, Some(dup_vec)); + let (mut lower_bounds, lower_vid_bounds, lower_dup) = + self.collect_bounding_regions(graph, node_idx, INCOMING, Some(dup_vec)); + let (mut upper_bounds, _, upper_dup) = + self.collect_bounding_regions(graph, node_idx, OUTGOING, Some(dup_vec)); if lower_dup || upper_dup { return; @@ -874,15 +877,22 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // If we have a scenario like `exists<'a> { forall<'b> { 'b: // 'a } }`, we wind up without any lower-bound -- all we have // are placeholders as upper bounds, but the universe of the - // variable `'a` doesn't permit those placeholders. + // variable `'a`, or some variable that `'a` has to outlive, doesn't + // permit those placeholders. + let min_universe = lower_vid_bounds + .into_iter() + .map(|vid| self.var_infos[vid].universe) + .min() + .expect("lower_vid_bounds should at least include `node_idx`"); + for upper_bound in &upper_bounds { if let ty::RePlaceholder(p) = upper_bound.region { - if node_universe.cannot_name(p.universe) { + if min_universe.cannot_name(p.universe) { let origin = self.var_infos[node_idx].origin; errors.push(RegionResolutionError::UpperBoundUniverseConflict( node_idx, origin, - node_universe, + min_universe, upper_bound.origin.clone(), upper_bound.region, )); @@ -904,13 +914,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ); } - fn collect_concrete_regions( + fn collect_bounding_regions( &self, graph: &RegionGraph<'tcx>, orig_node_idx: RegionVid, dir: Direction, mut dup_vec: Option<&mut IndexVec>>, - ) -> (Vec>, bool) { + ) -> (Vec>, FxHashSet, bool) { struct WalkState<'tcx> { set: FxHashSet, stack: Vec, @@ -929,9 +939,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // direction specified process_edges(&self.data, &mut state, graph, orig_node_idx, dir); - while !state.stack.is_empty() { - let node_idx = state.stack.pop().unwrap(); - + while let Some(node_idx) = state.stack.pop() { // check whether we've visited this node on some previous walk if let Some(dup_vec) = &mut dup_vec { if dup_vec[node_idx].is_none() { @@ -949,8 +957,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { process_edges(&self.data, &mut state, graph, node_idx, dir); } - let WalkState { result, dup_found, .. } = state; - return (result, dup_found); + let WalkState { result, dup_found, set, .. } = state; + return (result, set, dup_found); fn process_edges<'tcx>( this: &RegionConstraintData<'tcx>, From 187bfb333b6c801eb2a89364b033e9303d88387f Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 19 May 2020 20:18:39 +0100 Subject: [PATCH 159/695] Improve the error when an opaque type captures ReEmtpty --- src/librustc_infer/infer/error_reporting/mod.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index a8d6c01785ff9..91b8f6d2da412 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -297,7 +297,18 @@ pub fn unexpected_hidden_region_diagnostic( ); // Explain the region we are capturing. - if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) = hidden_region { + match hidden_region { + ty::ReEmpty(ty::UniverseIndex::ROOT) => { + // All lifetimes shorter than the function body are `empty` in + // lexical region resolution. The default explanation of "an empty + // lifetime" isn't really accurate here. + let message = format!( + "hidden type `{}` captures lifetime smaller than the function body", + hidden_ty + ); + err.span_note(span, &message); + } + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) => { // Assuming regionck succeeded (*), we ought to always be // capturing *some* region from the fn header, and hence it // ought to be free. So under normal circumstances, we will go @@ -313,7 +324,8 @@ pub fn unexpected_hidden_region_diagnostic( hidden_region, "", ); - } else { + } + _ => { // Ugh. This is a painful case: the hidden region is not one // that we can easily summarize or explain. This can happen // in a case like @@ -358,6 +370,7 @@ pub fn unexpected_hidden_region_diagnostic( ); } } + } err } From c102312c2ba5f3f679a606ed8cfafd3aa811bd29 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 19 May 2020 20:12:59 +0100 Subject: [PATCH 160/695] Remove the parts of regionck referencing ReScope --- src/librustc_typeck/check/regionck.rs | 509 +------------------------- 1 file changed, 17 insertions(+), 492 deletions(-) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 049f4767247c5..90ba15aa08988 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -83,12 +83,10 @@ use rustc_hir::PatKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, RegionObligation, RegionckMode}; use rustc_middle::ty::adjustment; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; use rustc_trait_selection::infer::OutlivesEnvironmentExt; use rustc_trait_selection::opaque_types::InferCtxtExt; -use std::mem; use std::ops::Deref; // a variation on try that just returns unit @@ -111,8 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn regionck_expr(&self, body: &'tcx hir::Body<'tcx>) { let subject = self.tcx.hir().body_owner_def_id(body.id()); let id = body.value.hir_id; - let mut rcx = - RegionCtxt::new(self, RepeatingScope(id), id, Subject(subject), self.param_env); + let mut rcx = RegionCtxt::new(self, id, Subject(subject), self.param_env); // There are no add'l implied bounds when checking a // standalone expr (e.g., the `E` in a type like `[u32; E]`). @@ -131,13 +128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: &[Ty<'tcx>]) { debug!("regionck_item(item.id={:?}, wf_tys={:?})", item_id, wf_tys); let subject = self.tcx.hir().local_def_id(item_id); - let mut rcx = RegionCtxt::new( - self, - RepeatingScope(item_id), - item_id, - Subject(subject), - self.param_env, - ); + let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env); rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span); rcx.outlives_environment.save_implied_bounds(item_id); rcx.visit_region_obligations(item_id); @@ -156,8 +147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("regionck_fn(id={})", fn_id); let subject = self.tcx.hir().body_owner_def_id(body.id()); let hir_id = body.value.hir_id; - let mut rcx = - RegionCtxt::new(self, RepeatingScope(hir_id), hir_id, Subject(subject), self.param_env); + let mut rcx = RegionCtxt::new(self, hir_id, Subject(subject), self.param_env); if !self.errors_reported_since_creation() { // regionck assumes typeck succeeded @@ -182,12 +172,6 @@ pub struct RegionCtxt<'a, 'tcx> { body_id: hir::HirId, body_owner: LocalDefId, - // call_site scope of innermost fn - call_site_scope: Option, - - // id of innermost fn or loop - repeating_scope: hir::HirId, - // id of AST node being analyzed (the subject of the analysis). subject_def_id: LocalDefId, } @@ -199,13 +183,11 @@ impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> { } } -pub struct RepeatingScope(hir::HirId); pub struct Subject(LocalDefId); impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { pub fn new( fcx: &'a FnCtxt<'a, 'tcx>, - RepeatingScope(initial_repeating_scope): RepeatingScope, initial_body_id: hir::HirId, Subject(subject): Subject, param_env: ty::ParamEnv<'tcx>, @@ -215,19 +197,13 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { RegionCtxt { fcx, region_scope_tree, - repeating_scope: initial_repeating_scope, body_id: initial_body_id, body_owner: subject, - call_site_scope: None, subject_def_id: subject, outlives_environment, } } - fn set_repeating_scope(&mut self, scope: hir::HirId) -> hir::HirId { - mem::replace(&mut self.repeating_scope, scope) - } - /// Try to resolve the type for the given node, returning `t_err` if an error results. Note that /// we never care about the details of the error, the same error will be detected and reported /// in the writeback phase. @@ -261,16 +237,10 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.resolve_type(t) } - /// Try to resolve the type for the given node. - pub fn resolve_expr_type_adjusted(&mut self, expr: &hir::Expr<'_>) -> Ty<'tcx> { - let ty = self.tables.borrow().expr_ty_adjusted(expr); - self.resolve_type(ty) - } - - /// This is the "main" function when region-checking a function item or a closure - /// within a function item. It begins by updating various fields (e.g., `call_site_scope` - /// and `outlives_environment`) to be appropriate to the function and then adds constraints - /// derived from the function body. + /// This is the "main" function when region-checking a function item or a + /// closure within a function item. It begins by updating various fields + /// (e.g., `outlives_environment`) to be appropriate to the function and + /// then adds constraints derived from the function body. /// /// Note that it does **not** restore the state of the fields that /// it updates! This is intentional, since -- for the main @@ -292,10 +262,6 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.body_id = body_id.hir_id; self.body_owner = self.tcx.hir().body_owner_def_id(body_id); - let call_site = - region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite }; - self.call_site_scope = Some(call_site); - let fn_sig = { match self.tables.borrow().liberated_fn_sigs().get(id) { Some(f) => *f, @@ -324,12 +290,6 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.visit_body(body); self.visit_region_obligations(body_id.hir_id); - let call_site_scope = self.call_site_scope.unwrap(); - debug!("visit_fn_body body.id {:?} call_site_scope: {:?}", body.id(), call_site_scope); - let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope)); - - self.type_of_node_must_outlive(infer::CallReturn(span), body_id.hir_id, call_site_region); - self.constrain_opaque_types( &self.fcx.opaque_types.borrow(), self.outlives_environment.free_region_map(), @@ -354,7 +314,6 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.fcx.resolve_regions_and_report_errors( self.subject_def_id.to_def_id(), - &self.region_scope_tree, &self.outlives_environment, mode, ); @@ -363,34 +322,6 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat<'_>) { debug!("regionck::visit_pat(pat={:?})", pat); pat.each_binding(|_, hir_id, span, _| { - // If we have a variable that contains region'd data, that - // data will be accessible from anywhere that the variable is - // accessed. We must be wary of loops like this: - // - // // from src/test/compile-fail/borrowck-lend-flow.rs - // let mut v = box 3, w = box 4; - // let mut x = &mut w; - // loop { - // **x += 1; // (2) - // borrow(v); //~ ERROR cannot borrow - // x = &mut v; // (1) - // } - // - // Typically, we try to determine the region of a borrow from - // those points where it is dereferenced. In this case, one - // might imagine that the lifetime of `x` need only be the - // body of the loop. But of course this is incorrect because - // the pointer that is created at point (1) is consumed at - // point (2), meaning that it must be live across the loop - // iteration. The easiest way to guarantee this is to require - // that the lifetime of any regions that appear in a - // variable's type enclose at least the variable's scope. - let var_scope = self.region_scope_tree.var_scope(hir_id.local_id); - let var_region = self.tcx.mk_region(ty::ReScope(var_scope)); - - let origin = infer::BindingTypeIsNotValidAtDecl(span); - self.type_of_node_must_outlive(origin, hir_id, var_region); - let typ = self.resolve_node_type(hir_id); let body_id = self.body_id; let _ = dropck::check_drop_obligations(self, typ, span, body_id); @@ -433,7 +364,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { // `visit_fn_body`. We will restore afterwards. let old_body_id = self.body_id; let old_body_owner = self.body_owner; - let old_call_site_scope = self.call_site_scope; let env_snapshot = self.outlives_environment.push_snapshot_pre_closure(); let body = self.tcx.hir().body(body_id); @@ -441,7 +371,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { // Restore state from previous function. self.outlives_environment.pop_snapshot_post_closure(env_snapshot); - self.call_site_scope = old_call_site_scope; self.body_id = old_body_id; self.body_owner = old_body_owner; } @@ -462,42 +391,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - debug!("regionck::visit_expr(e={:?}, repeating_scope={:?})", expr, self.repeating_scope); - - // No matter what, the type of each expression must outlive the - // scope of that expression. This also guarantees basic WF. - let expr_ty = self.resolve_node_type(expr.hir_id); - // the region corresponding to this expression - let expr_region = self.tcx.mk_region(ty::ReScope(region::Scope { - id: expr.hir_id.local_id, - data: region::ScopeData::Node, - })); - self.type_must_outlive( - infer::ExprTypeIsNotInScope(expr_ty, expr.span), - expr_ty, - expr_region, - ); - - let is_method_call = self.tables.borrow().is_method_call(expr); - - // If we are calling a method (either explicitly or via an - // overloaded operator), check that all of the types provided as - // arguments for its type parameters are well-formed, and all the regions - // provided as arguments outlive the call. - if is_method_call { - let origin = match expr.kind { - hir::ExprKind::MethodCall(..) => infer::ParameterOrigin::MethodCall, - hir::ExprKind::Unary(op, _) if op == hir::UnOp::UnDeref => { - infer::ParameterOrigin::OverloadedDeref - } - _ => infer::ParameterOrigin::OverloadedOperator, - }; - - let substs = self.tables.borrow().node_substs(expr.hir_id); - self.substs_wf_in_scope(origin, substs, expr.span, expr_region); - // Arguments (sub-expressions) are checked via `constrain_call`, below. - } - // Check any autoderefs or autorefs that appear. let cmt_result = self.constrain_adjustments(expr); @@ -512,117 +405,10 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { } } - debug!( - "regionck::visit_expr(e={:?}, repeating_scope={:?}) - visiting subexprs", - expr, self.repeating_scope - ); match expr.kind { - hir::ExprKind::Path(_) => { - let substs = self.tables.borrow().node_substs(expr.hir_id); - let origin = infer::ParameterOrigin::Path; - self.substs_wf_in_scope(origin, substs, expr.span, expr_region); - } - - hir::ExprKind::Call(ref callee, ref args) => { - if is_method_call { - self.constrain_call(expr, Some(&callee), args.iter().map(|e| &*e)); - } else { - self.constrain_callee(&callee); - self.constrain_call(expr, None, args.iter().map(|e| &*e)); - } - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::MethodCall(.., ref args) => { - self.constrain_call(expr, Some(&args[0]), args[1..].iter().map(|e| &*e)); - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { - if is_method_call { - self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); - } - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::Index(ref lhs, ref rhs) if is_method_call => { - self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::Binary(_, ref lhs, ref rhs) if is_method_call => { - // As `ExprKind::MethodCall`, but the call is via an overloaded op. - self.constrain_call(expr, Some(&lhs), Some(&**rhs).into_iter()); - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::Binary(_, ref lhs, ref rhs) => { - // If you do `x OP y`, then the types of `x` and `y` must - // outlive the operation you are performing. - let lhs_ty = self.resolve_expr_type_adjusted(&lhs); - let rhs_ty = self.resolve_expr_type_adjusted(&rhs); - for &ty in &[lhs_ty, rhs_ty] { - self.type_must_outlive(infer::Operand(expr.span), ty, expr_region); - } - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base) => { - // For *a, the lifetime of a must enclose the deref - if is_method_call { - self.constrain_call(expr, Some(base), None::>.iter()); - } - // For overloaded derefs, base_ty is the input to `Deref::deref`, - // but it's a reference type uing the same region as the output. - let base_ty = self.resolve_expr_type_adjusted(base); - if let ty::Ref(r_ptr, _, _) = base_ty.kind { - self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr); - } - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::Unary(_, ref lhs) if is_method_call => { - // As above. - self.constrain_call(expr, Some(&lhs), None::>.iter()); - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::Index(ref vec_expr, _) => { - // For a[b], the lifetime of a must enclose the deref - let vec_type = self.resolve_expr_type_adjusted(&vec_expr); - self.constrain_index(expr, vec_type); - - intravisit::walk_expr(self, expr); - } - - hir::ExprKind::Cast(ref source, _) => { - // Determine if we are casting `source` to a trait - // instance. If so, we have to be sure that the type of - // the source obeys the trait's region bound. - self.constrain_cast(expr, &source); - intravisit::walk_expr(self, expr); - } - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => { self.link_addr_of(expr, m, &base); - // Require that when you write a `&expr` expression, the - // resulting pointer has a lifetime that encompasses the - // `&expr` expression itself. Note that we constraining - // the type of the node expr.id here *before applying - // adjustments*. - // - // FIXME(https://github.com/rust-lang/rfcs/issues/811) - // nested method calls requires that this rule change - let ty0 = self.resolve_node_type(expr.hir_id); - self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region); intravisit::walk_expr(self, expr); } @@ -632,140 +418,12 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { intravisit::walk_expr(self, expr); } - hir::ExprKind::Closure(.., body_id, _, _) => { - self.check_expr_fn_block(expr, body_id); - } - - hir::ExprKind::Loop(ref body, _, _) => { - let repeating_scope = self.set_repeating_scope(body.hir_id); - intravisit::walk_expr(self, expr); - self.set_repeating_scope(repeating_scope); - } - - hir::ExprKind::Ret(Some(ref ret_expr)) => { - let call_site_scope = self.call_site_scope; - debug!( - "visit_expr ExprKind::Ret ret_expr.hir_id {} call_site_scope: {:?}", - ret_expr.hir_id, call_site_scope - ); - let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope.unwrap())); - self.type_of_node_must_outlive( - infer::CallReturn(ret_expr.span), - ret_expr.hir_id, - call_site_region, - ); - intravisit::walk_expr(self, expr); - } - - _ => { - intravisit::walk_expr(self, expr); - } + _ => intravisit::walk_expr(self, expr), } } } impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { - fn constrain_cast(&mut self, cast_expr: &hir::Expr<'_>, source_expr: &hir::Expr<'_>) { - debug!("constrain_cast(cast_expr={:?}, source_expr={:?})", cast_expr, source_expr); - - let source_ty = self.resolve_node_type(source_expr.hir_id); - let target_ty = self.resolve_node_type(cast_expr.hir_id); - - self.walk_cast(cast_expr, source_ty, target_ty); - } - - fn walk_cast(&mut self, cast_expr: &hir::Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) { - debug!("walk_cast(from_ty={:?}, to_ty={:?})", from_ty, to_ty); - match (&from_ty.kind, &to_ty.kind) { - /*From:*/ - (&ty::Ref(from_r, from_ty, _), /*To: */ &ty::Ref(to_r, to_ty, _)) => { - // Target cannot outlive source, naturally. - self.sub_regions(infer::Reborrow(cast_expr.span), to_r, from_r); - self.walk_cast(cast_expr, from_ty, to_ty); - } - - /*From:*/ - (_, /*To: */ &ty::Dynamic(.., r)) => { - // When T is existentially quantified as a trait - // `Foo+'to`, it must outlive the region bound `'to`. - self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), from_ty, r); - } - - /*From:*/ - (&ty::Adt(from_def, _), /*To: */ &ty::Adt(to_def, _)) - if from_def.is_box() && to_def.is_box() => - { - self.walk_cast(cast_expr, from_ty.boxed_ty(), to_ty.boxed_ty()); - } - - _ => {} - } - } - - fn check_expr_fn_block(&mut self, expr: &'tcx hir::Expr<'tcx>, body_id: hir::BodyId) { - let repeating_scope = self.set_repeating_scope(body_id.hir_id); - intravisit::walk_expr(self, expr); - self.set_repeating_scope(repeating_scope); - } - - fn constrain_callee(&mut self, callee_expr: &hir::Expr<'_>) { - let callee_ty = self.resolve_node_type(callee_expr.hir_id); - match callee_ty.kind { - ty::FnDef(..) | ty::FnPtr(_) => {} - _ => { - // this should not happen, but it does if the program is - // erroneous - // - // bug!( - // callee_expr.span, - // "Calling non-function: {}", - // callee_ty); - } - } - } - - fn constrain_call<'b, I: Iterator>>( - &mut self, - call_expr: &hir::Expr<'_>, - receiver: Option<&hir::Expr<'_>>, - arg_exprs: I, - ) { - //! Invoked on every call site (i.e., normal calls, method calls, - //! and overloaded operators). Constrains the regions which appear - //! in the type of the function. Also constrains the regions that - //! appear in the arguments appropriately. - - debug!("constrain_call(call_expr={:?}, receiver={:?})", call_expr, receiver); - - // `callee_region` is the scope representing the time in which the - // call occurs. - // - // FIXME(#6268) to support nested method calls, should be callee_id - let callee_scope = - region::Scope { id: call_expr.hir_id.local_id, data: region::ScopeData::Node }; - let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope)); - - debug!("callee_region={:?}", callee_region); - - for arg_expr in arg_exprs { - debug!("argument: {:?}", arg_expr); - - // ensure that any regions appearing in the argument type are - // valid for at least the lifetime of the function: - self.type_of_node_must_outlive( - infer::CallArg(arg_expr.span), - arg_expr.hir_id, - callee_region, - ); - } - - // as loop above, but for receiver - if let Some(r) = receiver { - debug!("receiver: {:?}", r); - self.type_of_node_must_outlive(infer::CallRcvr(r.span), r.hir_id, callee_region); - } - } - /// Creates a temporary `MemCategorizationContext` and pass it to the closure. fn with_mc(&self, f: F) -> R where @@ -784,79 +442,40 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { fn constrain_adjustments(&mut self, expr: &hir::Expr<'_>) -> mc::McResult> { debug!("constrain_adjustments(expr={:?})", expr); - let mut cmt = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; + let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; let tables = self.tables.borrow(); let adjustments = tables.expr_adjustments(&expr); if adjustments.is_empty() { - return Ok(cmt); + return Ok(place); } debug!("constrain_adjustments: adjustments={:?}", adjustments); // If necessary, constrain destructors in the unadjusted form of this // expression. - self.check_safety_of_rvalue_destructor_if_necessary(&cmt, expr.span); + self.check_safety_of_rvalue_destructor_if_necessary(&place, expr.span); - let expr_region = self.tcx.mk_region(ty::ReScope(region::Scope { - id: expr.hir_id.local_id, - data: region::ScopeData::Node, - })); for adjustment in adjustments { - debug!("constrain_adjustments: adjustment={:?}, cmt={:?}", adjustment, cmt); + debug!("constrain_adjustments: adjustment={:?}, place={:?}", adjustment, place); if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind { - debug!("constrain_adjustments: overloaded deref: {:?}", deref); - - // Treat overloaded autoderefs as if an AutoBorrow adjustment - // was applied on the base type, as that is always the case. - let input = self - .tcx - .mk_ref(deref.region, ty::TypeAndMut { ty: cmt.ty, mutbl: deref.mutbl }); - let output = self.tcx.mk_ref( - deref.region, - ty::TypeAndMut { ty: adjustment.target, mutbl: deref.mutbl }, - ); - self.link_region( expr.span, deref.region, ty::BorrowKind::from_mutbl(deref.mutbl), - &cmt, + &place, ); - - // Specialized version of constrain_call. - self.type_must_outlive(infer::CallRcvr(expr.span), input, expr_region); - self.type_must_outlive(infer::CallReturn(expr.span), output, expr_region); } if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind { - self.link_autoref(expr, &cmt, autoref); - - // Require that the resulting region encompasses - // the current node. - // - // FIXME(#6268) remove to support nested method calls - self.type_of_node_must_outlive( - infer::AutoBorrow(expr.span), - expr.hir_id, - expr_region, - ); + self.link_autoref(expr, &place, autoref); } - cmt = self.with_mc(|mc| mc.cat_expr_adjusted(expr, cmt, &adjustment))?; + place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, &adjustment))?; } - Ok(cmt) - } - - pub fn mk_subregion_due_to_dereference( - &mut self, - deref_span: Span, - minimum_lifetime: ty::Region<'tcx>, - maximum_lifetime: ty::Region<'tcx>, - ) { - self.sub_regions(infer::DerefPointer(deref_span), minimum_lifetime, maximum_lifetime) + Ok(place) } fn check_safety_of_rvalue_destructor_if_necessary( @@ -872,59 +491,6 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { } } } - - /// Invoked on any index expression that occurs. Checks that if this is a slice - /// being indexed, the lifetime of the pointer includes the deref expr. - fn constrain_index(&mut self, index_expr: &hir::Expr<'_>, indexed_ty: Ty<'tcx>) { - debug!("constrain_index(index_expr=?, indexed_ty={}", self.ty_to_string(indexed_ty)); - - let r_index_expr = ty::ReScope(region::Scope { - id: index_expr.hir_id.local_id, - data: region::ScopeData::Node, - }); - if let ty::Ref(r_ptr, r_ty, _) = indexed_ty.kind { - match r_ty.kind { - ty::Slice(_) | ty::Str => { - self.sub_regions( - infer::IndexSlice(index_expr.span), - self.tcx.mk_region(r_index_expr), - r_ptr, - ); - } - _ => {} - } - } - } - - /// Guarantees that any lifetimes that appear in the type of the node `id` (after applying - /// adjustments) are valid for at least `minimum_lifetime`. - fn type_of_node_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - hir_id: hir::HirId, - minimum_lifetime: ty::Region<'tcx>, - ) { - // Try to resolve the type. If we encounter an error, then typeck - // is going to fail anyway, so just stop here and let typeck - // report errors later on in the writeback phase. - let ty0 = self.resolve_node_type(hir_id); - - let ty = self - .tables - .borrow() - .adjustments() - .get(hir_id) - .and_then(|adj| adj.last()) - .map_or(ty0, |adj| adj.target); - let ty = self.resolve_type(ty); - debug!( - "constrain_regions_in_type_of_node(\ - ty={}, ty0={}, id={:?}, minimum_lifetime={:?})", - ty, ty0, hir_id, minimum_lifetime - ); - self.type_must_outlive(origin, ty, minimum_lifetime); - } - /// Adds constraints to inference such that `T: 'a` holds (or /// reports an error if it cannot). /// @@ -1035,13 +601,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m.into()), expr_cmt); } - adjustment::AutoBorrow::RawPtr(m) => { - let r = self.tcx.mk_region(ty::ReScope(region::Scope { - id: expr.hir_id.local_id, - data: region::ScopeData::Node, - })); - self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); - } + adjustment::AutoBorrow::RawPtr(_) => {} } } @@ -1251,39 +811,4 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { } } } - - /// Checks that the values provided for type/region arguments in a given - /// expression are well-formed and in-scope. - fn substs_wf_in_scope( - &mut self, - origin: infer::ParameterOrigin, - substs: SubstsRef<'tcx>, - expr_span: Span, - expr_region: ty::Region<'tcx>, - ) { - debug!( - "substs_wf_in_scope(substs={:?}, \ - expr_region={:?}, \ - origin={:?}, \ - expr_span={:?})", - substs, expr_region, origin, expr_span - ); - - let origin = infer::ParameterInScope(origin, expr_span); - - for kind in substs { - match kind.unpack() { - GenericArgKind::Lifetime(lt) => { - self.sub_regions(origin.clone(), expr_region, lt); - } - GenericArgKind::Type(ty) => { - let ty = self.resolve_type(ty); - self.type_must_outlive(origin.clone(), ty, expr_region); - } - GenericArgKind::Const(_) => { - // Const parameters don't impose constraints. - } - } - } - } } From 07b1de4e9a4a223840efd60475b86f815e84acfa Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 22 May 2020 09:50:41 -0700 Subject: [PATCH 161/695] Report error from opener in bootstrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On my machine, an error looks like: Finished release [optimized] target(s) in 0.29s Opening doc /git/rust/build/x86_64-unknown-linux-gnu/doc/std/index.html command 'xdg-open (internal)' did not execute successfully; exit code: 4 command stderr: gio: file:///git/rust/build/x86_64-unknown-linux-gnu/doc/std/index.html: Error when getting information for file “/git/rust/build/x86_64-unknown-linux-gnu/doc/std/index.html”: No such file or directory Build completed successfully in 0:00:08 --- src/bootstrap/doc.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index be5e3bfee303f..5c01c5e852c48 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -76,10 +76,10 @@ fn open(builder: &Builder<'_>, path: impl AsRef) { } let path = path.as_ref(); - builder.info(&format!("Opening doc {}", path.to_string_lossy())); - - // ignore error - let _ = opener::open(path); + builder.info(&format!("Opening doc {}", path.display())); + if let Err(err) = opener::open(path) { + builder.info(&format!("{}\n", err)); + } } // "src/libstd" -> ["src", "libstd"] From 7d73e4cc47f295e5b68fa7aa86688cabfd3c7eea Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 19 May 2020 20:26:24 +0100 Subject: [PATCH 162/695] Remove ReScope --- .../infer/canonical/canonicalizer.rs | 1 - src/librustc_infer/infer/combine.rs | 1 - .../infer/error_reporting/mod.rs | 45 ---- src/librustc_infer/infer/freshen.rs | 1 - .../infer/lexical_region_resolve/graphviz.rs | 253 ------------------ .../infer/lexical_region_resolve/mod.rs | 60 +---- .../infer/region_constraints/mod.rs | 8 +- src/librustc_middle/ich/impls_ty.rs | 3 - src/librustc_middle/ty/print/pretty.rs | 27 +- src/librustc_middle/ty/structural_impls.rs | 2 - src/librustc_middle/ty/sty.rs | 32 +-- .../borrow_check/diagnostics/region_name.rs | 1 - src/librustc_trait_selection/opaque_types.rs | 4 +- src/librustc_traits/chalk/lowering.rs | 1 - src/librustc_typeck/check/closure.rs | 18 +- src/librustc_typeck/check/mod.rs | 22 +- src/librustc_typeck/outlives/utils.rs | 1 - src/librustc_typeck/variance/constraints.rs | 1 - src/librustdoc/clean/mod.rs | 1 - 19 files changed, 27 insertions(+), 455 deletions(-) delete mode 100644 src/librustc_infer/infer/lexical_region_resolve/graphviz.rs diff --git a/src/librustc_infer/infer/canonical/canonicalizer.rs b/src/librustc_infer/infer/canonical/canonicalizer.rs index 5551b56ab797b..c2dae6ba4f83d 100644 --- a/src/librustc_infer/infer/canonical/canonicalizer.rs +++ b/src/librustc_infer/infer/canonical/canonicalizer.rs @@ -332,7 +332,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { ty::ReStatic | ty::ReEarlyBound(..) | ty::ReFree(_) - | ty::ReScope(_) | ty::ReEmpty(_) | ty::RePlaceholder(..) | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r), diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 75f288f1cdcd2..70a2122a9ea5d 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -619,7 +619,6 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { | ty::ReVar(..) | ty::ReEmpty(_) | ty::ReStatic - | ty::ReScope(..) | ty::ReEarlyBound(..) | ty::ReFree(..) => { // see common code below diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 91b8f6d2da412..66781e88c118a 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -88,51 +88,6 @@ pub(super) fn note_and_explain_region( suffix: &str, ) { let (description, span) = match *region { - ty::ReScope(scope) => { - let new_string; - let unknown_scope = - || format!("{}unknown scope: {:?}{}. Please report a bug.", prefix, scope, suffix); - let span = scope.span(tcx, region_scope_tree); - let hir_id = scope.hir_id(region_scope_tree); - let tag = match hir_id.and_then(|hir_id| tcx.hir().find(hir_id)) { - Some(Node::Block(_)) => "block", - Some(Node::Expr(expr)) => match expr.kind { - hir::ExprKind::Call(..) => "call", - hir::ExprKind::MethodCall(..) => "method call", - hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", - hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let", - hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for", - hir::ExprKind::Match(..) => "match", - _ => "expression", - }, - Some(Node::Stmt(_)) => "statement", - Some(Node::Item(it)) => item_scope_tag(&it), - Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), - Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), - Some(_) | None => { - err.span_note(span, &unknown_scope()); - return; - } - }; - let scope_decorated_tag = match scope.data { - region::ScopeData::Node => tag, - region::ScopeData::CallSite => "scope of call-site for function", - region::ScopeData::Arguments => "scope of function body", - region::ScopeData::Destruction => { - new_string = format!("destruction scope surrounding {}", tag); - &new_string[..] - } - region::ScopeData::Remainder(first_statement_index) => { - new_string = format!( - "block suffix following statement {}", - first_statement_index.index() - ); - &new_string[..] - } - }; - explain_span(tcx, scope_decorated_tag, span) - } - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { msg_span_from_free_region(tcx, region) } diff --git a/src/librustc_infer/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs index c9ed687eaf256..b4cfcb3a1c325 100644 --- a/src/librustc_infer/infer/freshen.rs +++ b/src/librustc_infer/infer/freshen.rs @@ -127,7 +127,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::ReStatic | ty::ReEarlyBound(..) | ty::ReFree(_) - | ty::ReScope(_) | ty::ReVar(_) | ty::RePlaceholder(..) | ty::ReEmpty(_) diff --git a/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs b/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs deleted file mode 100644 index 5d3e8f440d6fd..0000000000000 --- a/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs +++ /dev/null @@ -1,253 +0,0 @@ -//! This module provides linkage between libgraphviz traits and -//! `rustc_trait_selection::infer::region_constraints`, generating a -//! rendering of the graph represented by the list of `Constraint` -//! instances (which make up the edges of the graph), as well as the -//! origin for each constraint (which are attached to the labels on -//! each edge). - -/// For clarity, rename the graphviz crate locally to dot. -use graphviz as dot; - -use super::Constraint; -use crate::infer::region_constraints::RegionConstraintData; -use crate::infer::RegionRelations; -use crate::infer::SubregionOrigin; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::DefIndex; -use rustc_middle::middle::region; -use rustc_middle::ty; - -use std::borrow::Cow; -use std::collections::btree_map::BTreeMap; -use std::collections::hash_map::Entry::Vacant; -use std::env; -use std::fs; -use std::io; -use std::sync::atomic::{AtomicBool, Ordering}; - -fn print_help_message() { - println!( - "\ --Z print-region-graph by default prints a region constraint graph for every \n\ -function body, to the path `constraints.nodeXXX.dot`, where the XXX is \n\ -replaced with the node id of the function under analysis. \n\ - \n\ -To select one particular function body, set `RUST_REGION_GRAPH_NODE=XXX`, \n\ -where XXX is the node id desired. \n\ - \n\ -To generate output to some path other than the default \n\ -`constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`; \n\ -occurrences of the character `%` in the requested path will be replaced with\n\ -the node id of the function under analysis. \n\ - \n\ -(Since you requested help via RUST_REGION_GRAPH=help, no region constraint \n\ -graphs will be printed. \n\ -" - ); -} - -pub fn maybe_print_constraints_for<'a, 'tcx>( - region_data: &RegionConstraintData<'tcx>, - region_rels: &RegionRelations<'a, 'tcx>, -) { - let tcx = region_rels.tcx; - let context = region_rels.context; - - if !tcx.sess.opts.debugging_opts.print_region_graph { - return; - } - - let requested_node = env::var("RUST_REGION_GRAPH_NODE") - .ok() - .and_then(|s| s.parse().map(DefIndex::from_u32).ok()); - - if requested_node.is_some() && requested_node != Some(context.index) { - return; - } - - let requested_output = env::var("RUST_REGION_GRAPH"); - debug!("requested_output: {:?} requested_node: {:?}", requested_output, requested_node); - - let output_path = { - let output_template = match requested_output { - Ok(ref s) if s == "help" => { - static PRINTED_YET: AtomicBool = AtomicBool::new(false); - if !PRINTED_YET.load(Ordering::SeqCst) { - print_help_message(); - PRINTED_YET.store(true, Ordering::SeqCst); - } - return; - } - - Ok(other_path) => other_path, - Err(_) => "constraints.node%.dot".to_string(), - }; - - if output_template.is_empty() { - panic!("empty string provided as RUST_REGION_GRAPH"); - } - - if output_template.contains('%') { - let mut new_str = String::new(); - for c in output_template.chars() { - if c == '%' { - new_str.push_str(&context.index.as_u32().to_string()); - } else { - new_str.push(c); - } - } - new_str - } else { - output_template - } - }; - - if let Err(e) = dump_region_data_to(region_rels, ®ion_data.constraints, &output_path) { - let msg = format!("io error dumping region constraints: {}", e); - tcx.sess.err(&msg) - } -} - -struct ConstraintGraph<'a, 'tcx> { - graph_name: String, - region_rels: &'a RegionRelations<'a, 'tcx>, - map: &'a BTreeMap, SubregionOrigin<'tcx>>, - node_ids: FxHashMap, -} - -#[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)] -enum Node { - RegionVid(ty::RegionVid), - Region(ty::RegionKind), -} - -#[derive(Clone, PartialEq, Eq, Debug, Copy)] -enum Edge<'tcx> { - Constraint(Constraint<'tcx>), - EnclScope(region::Scope, region::Scope), -} - -impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> { - fn new( - name: String, - region_rels: &'a RegionRelations<'a, 'tcx>, - map: &'a ConstraintMap<'tcx>, - ) -> ConstraintGraph<'a, 'tcx> { - let mut i = 0; - let mut node_ids = FxHashMap::default(); - { - let mut add_node = |node| { - if let Vacant(e) = node_ids.entry(node) { - e.insert(i); - i += 1; - } - }; - - for (n1, n2) in map.keys().map(|c| constraint_to_nodes(c)) { - add_node(n1); - add_node(n2); - } - - region_rels.region_scope_tree.each_encl_scope(|sub, sup| { - add_node(Node::Region(ty::ReScope(sub))); - add_node(Node::Region(ty::ReScope(sup))); - }); - } - - ConstraintGraph { map, node_ids, region_rels, graph_name: name } - } -} - -impl<'a, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'tcx> { - type Node = Node; - type Edge = Edge<'tcx>; - fn graph_id(&self) -> dot::Id<'_> { - dot::Id::new(&*self.graph_name).unwrap() - } - fn node_id(&self, n: &Node) -> dot::Id<'_> { - let node_id = match self.node_ids.get(n) { - Some(node_id) => node_id, - None => bug!("no node_id found for node: {:?}", n), - }; - let name = || format!("node_{}", node_id); - - dot::Id::new(name()) - .unwrap_or_else(|_| bug!("failed to create graphviz node identified by {}", name())) - } - fn node_label(&self, n: &Node) -> dot::LabelText<'_> { - match *n { - Node::RegionVid(n_vid) => dot::LabelText::label(format!("{:?}", n_vid)), - Node::Region(n_rgn) => dot::LabelText::label(format!("{:?}", n_rgn)), - } - } - fn edge_label(&self, e: &Edge<'_>) -> dot::LabelText<'_> { - match *e { - Edge::Constraint(ref c) => { - dot::LabelText::label(format!("{:?}", self.map.get(c).unwrap())) - } - Edge::EnclScope(..) => dot::LabelText::label("(enclosed)".to_owned()), - } - } -} - -fn constraint_to_nodes(c: &Constraint<'_>) -> (Node, Node) { - match *c { - Constraint::VarSubVar(rv_1, rv_2) => (Node::RegionVid(rv_1), Node::RegionVid(rv_2)), - Constraint::RegSubVar(r_1, rv_2) => (Node::Region(*r_1), Node::RegionVid(rv_2)), - Constraint::VarSubReg(rv_1, r_2) => (Node::RegionVid(rv_1), Node::Region(*r_2)), - Constraint::RegSubReg(r_1, r_2) => (Node::Region(*r_1), Node::Region(*r_2)), - } -} - -fn edge_to_nodes(e: &Edge<'_>) -> (Node, Node) { - match *e { - Edge::Constraint(ref c) => constraint_to_nodes(c), - Edge::EnclScope(sub, sup) => { - (Node::Region(ty::ReScope(sub)), Node::Region(ty::ReScope(sup))) - } - } -} - -impl<'a, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'tcx> { - type Node = Node; - type Edge = Edge<'tcx>; - fn nodes(&self) -> dot::Nodes<'_, Node> { - let set = self.node_ids.keys().cloned().collect::>(); - debug!("constraint graph has {} nodes", set.len()); - set.into_iter().collect() - } - fn edges(&self) -> dot::Edges<'_, Edge<'tcx>> { - debug!("constraint graph has {} edges", self.map.len()); - let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect(); - self.region_rels - .region_scope_tree - .each_encl_scope(|sub, sup| v.push(Edge::EnclScope(sub, sup))); - debug!("region graph has {} edges", v.len()); - Cow::Owned(v) - } - fn source(&self, edge: &Edge<'tcx>) -> Node { - let (n1, _) = edge_to_nodes(edge); - debug!("edge {:?} has source {:?}", edge, n1); - n1 - } - fn target(&self, edge: &Edge<'tcx>) -> Node { - let (_, n2) = edge_to_nodes(edge); - debug!("edge {:?} has target {:?}", edge, n2); - n2 - } -} - -pub type ConstraintMap<'tcx> = BTreeMap, SubregionOrigin<'tcx>>; - -fn dump_region_data_to<'a, 'tcx>( - region_rels: &RegionRelations<'a, 'tcx>, - map: &ConstraintMap<'tcx>, - path: &str, -) -> io::Result<()> { - debug!("dump_region_data map (len: {}) path: {}", map.len(), path); - let g = ConstraintGraph::new("region_data".to_string(), region_rels, map); - debug!("dump_region_data calling render"); - let mut v = Vec::new(); - dot::render(&g, &mut v).unwrap(); - fs::write(path, &v) -} diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs index 5d64a987cbd0a..ef3eb24f28852 100644 --- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs @@ -18,13 +18,11 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; -use rustc_middle::ty::{ReLateBound, RePlaceholder, ReScope, ReVar}; +use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar}; use rustc_middle::ty::{Region, RegionVid}; use rustc_span::Span; use std::fmt; -mod graphviz; - /// This function performs lexical region resolution given a complete /// set of constraints and variable origins. It performs a fixed-point /// iteration to find region values which satisfy all constraints, @@ -149,7 +147,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.region_rels.context, self.dump_constraints(self.region_rels) ); - graphviz::maybe_print_constraints_for(&self.data, self.region_rels); let graph = self.construct_graph(); self.expand_givens(&graph); @@ -426,15 +423,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { match *b_data { VarValue::Value(cur_region) => { - // Identical scopes can show up quite often, if the fixed point - // iteration converges slowly. Skip them. This is purely an - // optimization. - if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) { - if a_scope == cur_scope { - return false; - } - } - // This is a specialized version of the `lub_concrete_regions` // check below for a common case, here purely as an // optimization. @@ -528,8 +516,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.tcx().lifetimes.re_static } - (&ReEmpty(_), r @ (ReEarlyBound(_) | ReFree(_) | ReScope(_))) - | (r @ (ReEarlyBound(_) | ReFree(_) | ReScope(_)), &ReEmpty(_)) => { + (&ReEmpty(_), r @ (ReEarlyBound(_) | ReFree(_))) + | (r @ (ReEarlyBound(_) | ReFree(_)), &ReEmpty(_)) => { // All empty regions are less than early-bound, free, // and scope regions. r @@ -554,46 +542,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } - (&ReEarlyBound(_) | &ReFree(_), &ReScope(s_id)) - | (&ReScope(s_id), &ReEarlyBound(_) | &ReFree(_)) => { - // A "free" region can be interpreted as "some region - // at least as big as fr.scope". So, we can - // reasonably compare free regions and scopes: - let fr_scope = match (a, b) { - (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => { - self.region_rels.region_scope_tree.early_free_scope(self.tcx(), br) - } - (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => { - self.region_rels.region_scope_tree.free_scope(self.tcx(), fr) - } - _ => bug!(), - }; - let r_id = - self.region_rels.region_scope_tree.nearest_common_ancestor(fr_scope, s_id); - if r_id == fr_scope { - // if the free region's scope `fr.scope` is bigger than - // the scope region `s_id`, then the LUB is the free - // region itself: - match (a, b) { - (_, &ReScope(_)) => return a, - (&ReScope(_), _) => return b, - _ => bug!(), - } - } - - // otherwise, we don't know what the free region is, - // so we must conservatively say the LUB is static: - self.tcx().lifetimes.re_static - } - - (&ReScope(a_id), &ReScope(b_id)) => { - // The region corresponding to an outer block is a - // subtype of the region corresponding to an inner - // block. - let lub = self.region_rels.region_scope_tree.nearest_common_ancestor(a_id, b_id); - self.tcx().mk_region(ReScope(lub)) - } - (&ReEarlyBound(_) | &ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => { self.region_rels.lub_free_regions(a, b) } @@ -662,7 +610,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { if !self.sub_concrete_regions(a_region, b_region) { debug!( "collect_errors: region error at {:?}: \ - cannot verify that {:?}={:?} <= {:?}", + cannot verify that {:?}={:?} <= {:?}", origin, a_vid, a_region, b_region ); *a_data = VarValue::ErrorValue; diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 3983e55717947..f45b224275574 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -758,11 +758,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex { match *region { - ty::ReScope(..) - | ty::ReStatic - | ty::ReErased - | ty::ReFree(..) - | ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT, + ty::ReStatic | ty::ReErased | ty::ReFree(..) | ty::ReEarlyBound(..) => { + ty::UniverseIndex::ROOT + } ty::ReEmpty(ui) => ui, ty::RePlaceholder(placeholder) => placeholder.universe, ty::ReVar(vid) => self.var_universe(vid), diff --git a/src/librustc_middle/ich/impls_ty.rs b/src/librustc_middle/ich/impls_ty.rs index 377c8661cbd41..ef6247881c0be 100644 --- a/src/librustc_middle/ich/impls_ty.rs +++ b/src/librustc_middle/ich/impls_ty.rs @@ -87,9 +87,6 @@ impl<'a> HashStable> for ty::RegionKind { index.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } - ty::ReScope(scope) => { - scope.hash_stable(hcx, hasher); - } ty::ReFree(ref free_region) => { free_region.hash_stable(hcx, hasher); } diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index f4b795e548867..f03d91aa64b78 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -1,5 +1,4 @@ use crate::middle::cstore::{ExternCrate, ExternCrateSource}; -use crate::middle::region; use crate::mir::interpret::{sign_extend, truncate, AllocId, ConstValue, Pointer, Scalar}; use crate::ty::layout::IntegerExt; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; @@ -1588,9 +1587,9 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { false } - ty::ReScope(_) | ty::ReVar(_) if identify_regions => true, + ty::ReVar(_) if identify_regions => true, - ty::ReVar(_) | ty::ReScope(_) | ty::ReErased => false, + ty::ReVar(_) | ty::ReErased => false, ty::ReStatic | ty::ReEmpty(_) => true, } @@ -1666,32 +1665,12 @@ impl FmtPrinter<'_, '_, F> { } } } - ty::ReScope(scope) if identify_regions => { - match scope.data { - region::ScopeData::Node => p!(write("'{}s", scope.item_local_id().as_usize())), - region::ScopeData::CallSite => { - p!(write("'{}cs", scope.item_local_id().as_usize())) - } - region::ScopeData::Arguments => { - p!(write("'{}as", scope.item_local_id().as_usize())) - } - region::ScopeData::Destruction => { - p!(write("'{}ds", scope.item_local_id().as_usize())) - } - region::ScopeData::Remainder(first_statement_index) => p!(write( - "'{}_{}rs", - scope.item_local_id().as_usize(), - first_statement_index.index() - )), - } - return Ok(self); - } ty::ReVar(region_vid) if identify_regions => { p!(write("{:?}", region_vid)); return Ok(self); } ty::ReVar(_) => {} - ty::ReScope(_) | ty::ReErased => {} + ty::ReErased => {} ty::ReStatic => { p!(write("'static")); return Ok(self); diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index babe0c54801e8..569a8d90bfcc3 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -87,8 +87,6 @@ impl fmt::Debug for ty::RegionKind { ty::ReFree(ref fr) => fr.fmt(f), - ty::ReScope(id) => write!(f, "ReScope({:?})", id), - ty::ReStatic => write!(f, "ReStatic"), ty::ReVar(ref vid) => vid.fmt(f), diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 0c9eef8093f33..370702f7f221d 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -6,7 +6,6 @@ use self::InferTy::*; use self::TyKind::*; use crate::infer::canonical::Canonical; -use crate::middle::region; use crate::mir::interpret::ConstValue; use crate::mir::interpret::{LitToConstInput, Scalar}; use crate::mir::Promoted; @@ -1179,17 +1178,15 @@ rustc_index::newtype_index! { pub type Region<'tcx> = &'tcx RegionKind; -/// Representation of (lexical) regions. Note that the NLL checker -/// uses a distinct representation of regions. For this reason, it -/// internally replaces all the regions with inference variables -- -/// the index of the variable is then used to index into internal NLL -/// data structures. See `rustc_mir::borrow_check` module for more -/// information. +/// Representation of regions. Note that the NLL checker uses a distinct +/// representation of regions. For this reason, it internally replaces all the +/// regions with inference variables -- the index of the variable is then used +/// to index into internal NLL data structures. See `rustc_mir::borrow_check` +/// module for more information. /// /// ## The Region lattice within a given function /// -/// In general, the (lexical, and hence deprecated) region lattice -/// looks like +/// In general, the region lattice looks like /// /// ``` /// static ----------+-----...------+ (greatest) @@ -1197,7 +1194,6 @@ pub type Region<'tcx> = &'tcx RegionKind; /// early-bound and | | /// free regions | | /// | | | -/// scope regions | | /// | | | /// empty(root) placeholder(U1) | /// | / | @@ -1212,13 +1208,7 @@ pub type Region<'tcx> = &'tcx RegionKind; /// Early-bound/free regions are the named lifetimes in scope from the /// function declaration. They have relationships to one another /// determined based on the declared relationships from the -/// function. They all collectively outlive the scope regions. (See -/// `RegionRelations` type, and particularly -/// `crate::infer::outlives::free_region_map::FreeRegionMap`.) -/// -/// The scope regions are related to one another based on the AST -/// structure. (See `RegionRelations` type, and particularly the -/// `rustc_middle::middle::region::ScopeTree`.) +/// function. /// /// Note that inference variables and bound regions are not included /// in this diagram. In the case of inference variables, they should @@ -1307,11 +1297,6 @@ pub enum RegionKind { /// region parameters. ReFree(FreeRegion), - /// A concrete region naming some statically determined scope - /// (e.g., an expression or sequence of statements) within the - /// current function. - ReScope(region::Scope), - /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, @@ -1535,7 +1520,6 @@ impl RegionKind { RegionKind::ReEarlyBound(ebr) => ebr.has_name(), RegionKind::ReLateBound(_, br) => br.is_named(), RegionKind::ReFree(fr) => fr.bound_region.is_named(), - RegionKind::ReScope(..) => false, RegionKind::ReStatic => true, RegionKind::ReVar(..) => false, RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(), @@ -1616,7 +1600,7 @@ impl RegionKind { flags = flags | TypeFlags::HAS_RE_PARAM; flags = flags | TypeFlags::STILL_FURTHER_SPECIALIZABLE; } - ty::ReFree { .. } | ty::ReScope { .. } => { + ty::ReFree { .. } => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; } diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs index 37e2e0475048d..e912ef7b20202 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs @@ -284,7 +284,6 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { }, ty::ReLateBound(..) - | ty::ReScope(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReEmpty(_) diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 2544e4ddea2ec..d14ae40b45a0b 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -670,7 +670,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // `least_region`. We cannot use `push_outlives_components` because regions in // closure signatures are not included in their outlives components. We need to // ensure all regions outlive the given bound so that we don't end up with, -// say, `ReScope` appearing in a return type and causing ICEs when other +// say, `ReVar` appearing in a return type and causing ICEs when other // functions end up with region constraints involving regions from other // functions. // @@ -816,7 +816,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { // The regions that we expect from borrow checking. ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} - ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) | ty::ReScope(_) => { + ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => { // All of the regions in the type should either have been // erased by writeback, or mapped back to named regions by // borrow checking. diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index 7d48b45753810..a33ada2fb6ef1 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -394,7 +394,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t ty::BrEnv => unimplemented!(), }, ReFree(_) => unimplemented!(), - ReScope(_) => unimplemented!(), ReStatic => unimplemented!(), ReVar(_) => unimplemented!(), RePlaceholder(placeholder_region) => { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index f393121a0adb8..1b7fde69830f0 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -12,7 +12,7 @@ use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty}; +use rustc_middle::ty::{self, GenericParamDefKind, Ty}; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::ArgKind; @@ -518,22 +518,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let InferOk { value: (), obligations } = self.at(&cause, self.param_env).eq(*expected_ty, supplied_ty)?; all_obligations.extend(obligations); - - // Also, require that the supplied type must outlive - // the closure body. - let closure_body_region = self.tcx.mk_region(ty::ReScope(region::Scope { - id: body.value.hir_id.local_id, - data: region::ScopeData::Node, - })); - all_obligations.push(Obligation::new( - cause, - self.param_env, - ty::PredicateKind::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( - supplied_ty, - closure_body_region, - ))) - .to_predicate(self.tcx), - )); } let (supplied_output_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c452859414cfb..6b7adb728e7e6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -106,13 +106,13 @@ use rustc_hir::lang_items::{ use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; +use rustc_infer::infer; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_infer::infer::{self, InferCtxt, InferOk, InferResult, TyCtxtInferExt}; +use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TyCtxtInferExt}; use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::middle::region; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, @@ -667,13 +667,6 @@ impl Inherited<'a, 'tcx> { let tcx = infcx.tcx; let item_id = tcx.hir().local_def_id_to_hir_id(def_id); let body_id = tcx.hir().maybe_body_owned_by(item_id); - let implicit_region_bound = body_id.map(|body_id| { - let body = tcx.hir().body(body_id); - tcx.mk_region(ty::ReScope(region::Scope { - id: body.value.hir_id.local_id, - data: region::ScopeData::CallSite, - })) - }); Inherited { tables: MaybeInProgressTables { maybe_tables: infcx.in_progress_tables }, @@ -686,7 +679,7 @@ impl Inherited<'a, 'tcx> { deferred_generator_interiors: RefCell::new(Vec::new()), opaque_types: RefCell::new(Default::default()), opaque_types_vars: RefCell::new(Default::default()), - implicit_region_bound, + implicit_region_bound: None, body_id, } } @@ -1337,12 +1330,9 @@ fn check_fn<'a, 'tcx>( // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). let maybe_va_list = if fn_sig.c_variadic { - let va_list_did = - tcx.require_lang_item(VaListTypeLangItem, Some(body.params.last().unwrap().span)); - let region = tcx.mk_region(ty::ReScope(region::Scope { - id: body.value.hir_id.local_id, - data: region::ScopeData::CallSite, - })); + let span = body.params.last().unwrap().span; + let va_list_did = tcx.require_lang_item(VaListTypeLangItem, Some(span)); + let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) } else { diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs index 3bbe3e34a6a45..8b06967879638 100644 --- a/src/librustc_typeck/outlives/utils.rs +++ b/src/librustc_typeck/outlives/utils.rs @@ -170,7 +170,6 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool { // These regions don't appear in types from type declarations: RegionKind::ReErased - | RegionKind::ReScope(..) | RegionKind::ReVar(..) | RegionKind::RePlaceholder(..) | RegionKind::ReFree(..) => { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 3a680f55c8c30..e04af6850dea1 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -444,7 +444,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::ReFree(..) - | ty::ReScope(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReEmpty(_) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cf1a39232bc78..702c7d1e0f120 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -447,7 +447,6 @@ impl Clean> for ty::RegionKind { ty::ReLateBound(..) | ty::ReFree(..) - | ty::ReScope(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReEmpty(_) From 52d628f250d96941affb01f09cc951f802f15d7e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 19 May 2020 21:25:07 +0100 Subject: [PATCH 163/695] Remove unused error reporting code --- .../error_reporting/nice_region_error/mod.rs | 2 - .../nice_region_error/outlives_closure.rs | 117 ------ .../infer/error_reporting/note.rs | 355 ------------------ src/librustc_infer/infer/mod.rs | 62 --- 4 files changed, 536 deletions(-) delete mode 100644 src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs index 2aed3d9a469fb..efe52689550c4 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs @@ -8,7 +8,6 @@ use rustc_span::source_map::Span; mod different_lifetimes; mod find_anon_type; mod named_anon_conflict; -mod outlives_closure; mod placeholder_error; mod static_impl_trait; mod trait_impl_difference; @@ -57,7 +56,6 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { ErrorReported }) .or_else(|| self.try_report_anon_anon_conflict()) - .or_else(|| self.try_report_outlives_closure()) .or_else(|| self.try_report_static_impl_trait()) .or_else(|| self.try_report_impl_not_conforming_to_trait()) } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs deleted file mode 100644 index fc858a497597e..0000000000000 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Error Reporting for Anonymous Region Lifetime Errors -//! where both the regions are anonymous. - -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError::SubSupConflict; -use crate::infer::SubregionOrigin; -use rustc_errors::ErrorReported; -use rustc_hir::{Expr, ExprKind::Closure, Node}; -use rustc_middle::ty::RegionKind; - -impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// Print the error message for lifetime errors when binding escapes a closure. - /// - /// Consider a case where we have - /// - /// ```no_run - /// fn with_int(f: F) where F: FnOnce(&isize) { - /// let x = 3; - /// f(&x); - /// } - /// fn main() { - /// let mut x = None; - /// with_int(|y| x = Some(y)); - /// } - /// ``` - /// - /// the output will be - /// - /// ```text - /// let mut x = None; - /// ----- borrowed data cannot be stored into here... - /// with_int(|y| x = Some(y)); - /// --- ^ cannot be stored outside of its closure - /// | - /// ...because it cannot outlive this closure - /// ``` - pub(super) fn try_report_outlives_closure(&self) -> Option { - if let Some(SubSupConflict(_, origin, ref sub_origin, _, ref sup_origin, sup_region)) = - self.error - { - // #45983: when trying to assign the contents of an argument to a binding outside of a - // closure, provide a specific message pointing this out. - if let ( - &SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span), - &RegionKind::ReFree(ref free_region), - ) = (&sub_origin, sup_region) - { - let hir = &self.tcx().hir(); - if let Some(def_id) = free_region.scope.as_local() { - let hir_id = hir.as_local_hir_id(def_id); - if let Node::Expr(Expr { kind: Closure(_, _, _, closure_span, None), .. }) = - hir.get(hir_id) - { - let sup_sp = sup_origin.span(); - let origin_sp = origin.span(); - let mut err = self.tcx().sess.struct_span_err( - sup_sp, - "borrowed data cannot be stored outside of its closure", - ); - err.span_label(sup_sp, "cannot be stored outside of its closure"); - if origin_sp == sup_sp || origin_sp.contains(sup_sp) { - // // sup_sp == origin.span(): - // - // let mut x = None; - // ----- borrowed data cannot be stored into here... - // with_int(|y| x = Some(y)); - // --- ^ cannot be stored outside of its closure - // | - // ...because it cannot outlive this closure - // - // // origin.contains(&sup_sp): - // - // let mut f: Option<&u32> = None; - // ----- borrowed data cannot be stored into here... - // closure_expecting_bound(|x: &'x u32| { - // ------------ ... because it cannot outlive this closure - // f = Some(x); - // ^ cannot be stored outside of its closure - err.span_label( - *external_span, - "borrowed data cannot be stored into here...", - ); - err.span_label( - *closure_span, - "...because it cannot outlive this closure", - ); - } else { - // FIXME: the wording for this case could be much improved - // - // let mut lines_to_use: Vec<&CrateId> = Vec::new(); - // - cannot infer an appropriate lifetime... - // let push_id = |installed_id: &CrateId| { - // ------- ------------------------ borrowed data cannot outlive this closure - // | - // ...so that variable is valid at time of its declaration - // lines_to_use.push(installed_id); - // ^^^^^^^^^^^^ cannot be stored outside of its closure - err.span_label(origin_sp, "cannot infer an appropriate lifetime..."); - err.span_label( - *external_span, - "...so that variable is valid at time of its \ - declaration", - ); - err.span_label( - *closure_span, - "borrowed data cannot outlive this closure", - ); - } - err.emit(); - return Some(ErrorReported); - } - } - } - } - None - } -} diff --git a/src/librustc_infer/infer/error_reporting/note.rs b/src/librustc_infer/infer/error_reporting/note.rs index 81f37831af208..a4e51fe0b1c00 100644 --- a/src/librustc_infer/infer/error_reporting/note.rs +++ b/src/librustc_infer/infer/error_reporting/note.rs @@ -38,65 +38,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); err.span_note(span, &format!("...so that closure can access `{}`", var_name)); } - infer::InfStackClosure(span) => { - err.span_note(span, "...so that closure does not outlive its stack frame"); - } - infer::InvokeClosure(span) => { - err.span_note(span, "...so that closure is not invoked outside its lifetime"); - } - infer::DerefPointer(span) => { - err.span_note(span, "...so that pointer is not dereferenced outside its lifetime"); - } - infer::ClosureCapture(span, id) => { - err.span_note( - span, - &format!( - "...so that captured variable `{}` does not outlive the \ - enclosing closure", - self.tcx.hir().name(id) - ), - ); - } - infer::IndexSlice(span) => { - err.span_note(span, "...so that slice is not indexed outside the lifetime"); - } infer::RelateObjectBound(span) => { err.span_note(span, "...so that it can be closed over into an object"); } - infer::CallRcvr(span) => { - err.span_note(span, "...so that method receiver is valid for the method call"); - } - infer::CallArg(span) => { - err.span_note(span, "...so that argument is valid for the call"); - } infer::CallReturn(span) => { err.span_note(span, "...so that return value is valid for the call"); } - infer::Operand(span) => { - err.span_note(span, "...so that operand is valid for operation"); - } - infer::AddrOf(span) => { - err.span_note(span, "...so that reference is valid at the time of borrow"); - } - infer::AutoBorrow(span) => { - err.span_note(span, "...so that auto-reference is valid at the time of borrow"); - } - infer::ExprTypeIsNotInScope(t, span) => { - err.span_note( - span, - &format!( - "...so type `{}` of expression is valid during the \ - expression", - self.ty_to_string(t) - ), - ); - } - infer::BindingTypeIsNotValidAtDecl(span) => { - err.span_note(span, "...so that variable is valid at time of its declaration"); - } - infer::ParameterInScope(_, span) => { - err.span_note(span, "...so that a type/lifetime parameter is in scope here"); - } infer::DataBorrowed(ty, span) => { err.span_note( span, @@ -126,25 +73,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ), ); } - infer::RelateDefaultParamBound(span, t) => { - err.span_note( - span, - &format!( - "...so that type parameter instantiated with `{}`, will \ - meet its declared lifetime bounds", - self.ty_to_string(t) - ), - ); - } infer::RelateRegionParamBound(span) => { err.span_note( span, "...so that the declared lifetime parameter bounds are satisfied", ); } - infer::SafeDestructor(span) => { - err.span_note(span, "...so that references are valid when the destructor runs"); - } infer::CompareImplMethodObligation { span, .. } => { err.span_note( span, @@ -231,106 +165,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); err } - infer::InfStackClosure(span) => { - let mut err = - struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame"); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...the closure must be valid for ", - sub, - "...", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...but the closure's stack frame is only valid \ - for ", - sup, - "", - ); - err - } - infer::InvokeClosure(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0315, - "cannot invoke closure outside of its lifetime" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the closure is only valid for ", - sup, - "", - ); - err - } - infer::DerefPointer(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0473, - "dereference of reference outside its lifetime" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the reference is only valid for ", - sup, - "", - ); - err - } - infer::ClosureCapture(span, id) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0474, - "captured variable `{}` does not outlive the \ - enclosing closure", - self.tcx.hir().name(id) - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "captured variable is valid for ", - sup, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "closure is valid for ", - sub, - "", - ); - err - } - infer::IndexSlice(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0475, - "index of slice outside its lifetime" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the slice is only valid for ", - sup, - "", - ); - err - } infer::RelateObjectBound(span) => { let mut err = struct_span_err!( self.tcx.sess, @@ -407,61 +241,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); err } - infer::RelateDefaultParamBound(span, ty) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0479, - "the type `{}` (provided as the value of a type \ - parameter) is not valid at this point", - self.ty_to_string(ty) - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "type must outlive ", - sub, - "", - ); - err - } - infer::CallRcvr(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0480, - "lifetime of method receiver does not outlive the \ - method call" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the receiver is only valid for ", - sup, - "", - ); - err - } - infer::CallArg(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0481, - "lifetime of function argument does not outlive \ - the function call" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the function argument is only valid for ", - sup, - "", - ); - err - } infer::CallReturn(span) => { let mut err = struct_span_err!( self.tcx.sess, @@ -480,140 +259,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); err } - infer::Operand(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0483, - "lifetime of operand does not outlive the \ - operation" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the operand is only valid for ", - sup, - "", - ); - err - } - infer::AddrOf(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0484, - "reference is not valid at the time of borrow" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the borrow is only valid for ", - sup, - "", - ); - err - } - infer::AutoBorrow(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0485, - "automatically reference is not valid at the time \ - of borrow" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the automatic borrow is only valid for ", - sup, - "", - ); - err - } - infer::ExprTypeIsNotInScope(t, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0486, - "type of expression contains references that are \ - not valid during the expression: `{}`", - self.ty_to_string(t) - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "type is only valid for ", - sup, - "", - ); - err - } - infer::SafeDestructor(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0487, - "unsafe use of destructor: destructor might be \ - called while references are dead" - ); - // FIXME (22171): terms "super/subregion" are suboptimal - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "superregion: ", - sup, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "subregion: ", - sub, - "", - ); - err - } - infer::BindingTypeIsNotValidAtDecl(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0488, - "lifetime of variable does not enclose its \ - declaration" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the variable is only valid for ", - sup, - "", - ); - err - } - infer::ParameterInScope(_, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0489, - "type/lifetime parameter not in scope here" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the parameter is only valid for ", - sub, - "", - ); - err - } infer::DataBorrowed(ty, span) => { let mut err = struct_span_err!( self.tcx.sess, diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 9c81a1153958b..fdd0c5b2ff368 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -378,22 +378,6 @@ pub enum SubregionOrigin<'tcx> { /// Arose from a subtyping relation Subtype(Box>), - /// Stack-allocated closures cannot outlive innermost loop - /// or function so as to ensure we only require finite stack - InfStackClosure(Span), - - /// Invocation of closure must be within its lifetime - InvokeClosure(Span), - - /// Dereference of reference must be within its lifetime - DerefPointer(Span), - - /// Closure bound must not outlive captured variables - ClosureCapture(Span, hir::HirId), - - /// Index into slice must be within its lifetime - IndexSlice(Span), - /// When casting `&'a T` to an `&'b Trait` object, /// relating `'a` to `'b` RelateObjectBound(Span), @@ -406,10 +390,6 @@ pub enum SubregionOrigin<'tcx> { /// that must outlive some other region. RelateRegionParamBound(Span), - /// A bound placed on type parameters that states that must outlive - /// the moment of their instantiation. - RelateDefaultParamBound(Span, Ty<'tcx>), - /// Creating a pointer `b` to contents of another reference Reborrow(Span), @@ -422,36 +402,9 @@ pub enum SubregionOrigin<'tcx> { /// (&'a &'b T) where a >= b ReferenceOutlivesReferent(Ty<'tcx>, Span), - /// Type or region parameters must be in scope. - ParameterInScope(ParameterOrigin, Span), - - /// The type T of an expression E must outlive the lifetime for E. - ExprTypeIsNotInScope(Ty<'tcx>, Span), - - /// A `ref b` whose region does not enclose the decl site - BindingTypeIsNotValidAtDecl(Span), - - /// Regions appearing in a method receiver must outlive method call - CallRcvr(Span), - - /// Regions appearing in a function argument must outlive func call - CallArg(Span), - /// Region in return type of invoked fn must enclose call CallReturn(Span), - /// Operands must be in scope - Operand(Span), - - /// Region resulting from a `&` expr must enclose the `&` expr - AddrOf(Span), - - /// An auto-borrow that does not enclose the expr where it occurs - AutoBorrow(Span), - - /// Region constraint arriving from destructor safety - SafeDestructor(Span), - /// Comparing the signature and requirements of an impl method against /// the containing trait. CompareImplMethodObligation { @@ -1809,29 +1762,14 @@ impl<'tcx> SubregionOrigin<'tcx> { pub fn span(&self) -> Span { match *self { Subtype(ref a) => a.span(), - InfStackClosure(a) => a, - InvokeClosure(a) => a, - DerefPointer(a) => a, - ClosureCapture(a, _) => a, - IndexSlice(a) => a, RelateObjectBound(a) => a, RelateParamBound(a, _) => a, RelateRegionParamBound(a) => a, - RelateDefaultParamBound(a, _) => a, Reborrow(a) => a, ReborrowUpvar(a, _) => a, DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, - ParameterInScope(_, a) => a, - ExprTypeIsNotInScope(_, a) => a, - BindingTypeIsNotValidAtDecl(a) => a, - CallRcvr(a) => a, - CallArg(a) => a, CallReturn(a) => a, - Operand(a) => a, - AddrOf(a) => a, - AutoBorrow(a) => a, - SafeDestructor(a) => a, CompareImplMethodObligation { span, .. } => span, } } From 3d8a0733ae58749db958e929aa14108b869f7540 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 19 May 2020 21:26:18 +0100 Subject: [PATCH 164/695] Remove dead ScopeTree code --- .../infer/error_reporting/mod.rs | 139 +++++---------- .../infer/error_reporting/note.rs | 73 ++------ src/librustc_infer/infer/free_regions.rs | 13 +- src/librustc_infer/infer/mod.rs | 12 +- src/librustc_middle/middle/region.rs | 160 +----------------- .../borrow_check/diagnostics/region_errors.rs | 4 - src/librustc_trait_selection/opaque_types.rs | 1 - src/librustc_trait_selection/traits/mod.rs | 4 - src/librustc_typeck/check/closure.rs | 2 - src/librustc_typeck/check/dropck.rs | 4 - src/librustc_typeck/coherence/builtin.rs | 11 +- .../impl_wf_check/min_specialization.rs | 8 +- 12 files changed, 57 insertions(+), 374 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 66781e88c118a..cc479aa17ce95 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -61,7 +61,6 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::Node; -use rustc_middle::middle::region; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, @@ -81,7 +80,6 @@ pub mod nice_region_error; pub(super) fn note_and_explain_region( tcx: TyCtxt<'tcx>, - region_scope_tree: ®ion::ScopeTree, err: &mut DiagnosticBuilder<'_>, prefix: &str, region: ty::Region<'tcx>, @@ -239,7 +237,6 @@ fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option pub fn unexpected_hidden_region_diagnostic( tcx: TyCtxt<'tcx>, - region_scope_tree: Option<®ion::ScopeTree>, span: Span, hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, @@ -264,78 +261,53 @@ pub fn unexpected_hidden_region_diagnostic( err.span_note(span, &message); } ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) => { - // Assuming regionck succeeded (*), we ought to always be - // capturing *some* region from the fn header, and hence it - // ought to be free. So under normal circumstances, we will go - // down this path which gives a decent human readable - // explanation. - // - // (*) if not, the `tainted_by_errors` field would be set to - // `Some(ErrorReported)` in any case, so we wouldn't be here at all. - note_and_explain_free_region( - tcx, - &mut err, - &format!("hidden type `{}` captures ", hidden_ty), - hidden_region, - "", - ); + // Assuming regionck succeeded (*), we ought to always be + // capturing *some* region from the fn header, and hence it + // ought to be free. So under normal circumstances, we will go + // down this path which gives a decent human readable + // explanation. + // + // (*) if not, the `tainted_by_errors` field would be set to + // `Some(ErrorReported)` in any case, so we wouldn't be here at all. + note_and_explain_free_region( + tcx, + &mut err, + &format!("hidden type `{}` captures ", hidden_ty), + hidden_region, + "", + ); } _ => { - // Ugh. This is a painful case: the hidden region is not one - // that we can easily summarize or explain. This can happen - // in a case like - // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: - // - // ``` - // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> { - // if condition() { a } else { b } - // } - // ``` - // - // Here the captured lifetime is the intersection of `'a` and - // `'b`, which we can't quite express. - - if let Some(region_scope_tree) = region_scope_tree { - // If the `region_scope_tree` is available, this is being - // invoked from the "region inferencer error". We can at - // least report a really cryptic error for now. + // Ugh. This is a painful case: the hidden region is not one + // that we can easily summarize or explain. This can happen + // in a case like + // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: + // + // ``` + // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> { + // if condition() { a } else { b } + // } + // ``` + // + // Here the captured lifetime is the intersection of `'a` and + // `'b`, which we can't quite express. + + // We can at least report a really cryptic error for now. note_and_explain_region( tcx, - region_scope_tree, &mut err, &format!("hidden type `{}` captures ", hidden_ty), hidden_region, "", ); - } else { - // If the `region_scope_tree` is *unavailable*, this is - // being invoked by the code that comes *after* region - // inferencing. This is a bug, as the region inferencer - // ought to have noticed the failed constraint and invoked - // error reporting, which in turn should have prevented us - // from getting trying to infer the hidden type - // completely. - tcx.sess.delay_span_bug( - span, - &format!( - "hidden type captures unexpected lifetime `{:?}` \ - but no region inference failure", - hidden_region, - ), - ); } } - } err } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_region_errors( - &self, - region_scope_tree: ®ion::ScopeTree, - errors: &Vec>, - ) { + pub fn report_region_errors(&self, errors: &Vec>) { debug!("report_region_errors(): {} errors to start", errors.len()); // try to pre-process the errors, which will group some of them @@ -358,17 +330,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // general bit of code that displays the error information RegionResolutionError::ConcreteFailure(origin, sub, sup) => { if sub.is_placeholder() || sup.is_placeholder() { - self.report_placeholder_failure(region_scope_tree, origin, sub, sup) - .emit(); + self.report_placeholder_failure(origin, sub, sup).emit(); } else { - self.report_concrete_failure(region_scope_tree, origin, sub, sup) - .emit(); + self.report_concrete_failure(origin, sub, sup).emit(); } } RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => { self.report_generic_bound_failure( - region_scope_tree, origin.span(), Some(origin), param_ty, @@ -385,29 +354,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sup_r, ) => { if sub_r.is_placeholder() { - self.report_placeholder_failure( - region_scope_tree, - sub_origin, - sub_r, - sup_r, - ) - .emit(); + self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit(); } else if sup_r.is_placeholder() { - self.report_placeholder_failure( - region_scope_tree, - sup_origin, - sub_r, - sup_r, - ) - .emit(); + self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } else { self.report_sub_sup_conflict( - region_scope_tree, - var_origin, - sub_origin, - sub_r, - sup_origin, - sup_r, + var_origin, sub_origin, sub_r, sup_origin, sup_r, ); } } @@ -428,13 +380,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // value. let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe)); - self.report_placeholder_failure( - region_scope_tree, - sup_origin, - sub_r, - sup_r, - ) - .emit(); + self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } RegionResolutionError::MemberConstraintFailure { @@ -445,7 +391,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); unexpected_hidden_region_diagnostic( self.tcx, - Some(region_scope_tree), span, hidden_ty, member_region, @@ -1722,19 +1667,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_generic_bound_failure( &self, - region_scope_tree: ®ion::ScopeTree, span: Span, origin: Option>, bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, ) { - self.construct_generic_bound_failure(region_scope_tree, span, origin, bound_kind, sub) - .emit(); + self.construct_generic_bound_failure(span, origin, bound_kind, sub).emit(); } pub fn construct_generic_bound_failure( &self, - region_scope_tree: ®ion::ScopeTree, span: Span, origin: Option>, bound_kind: GenericKind<'tcx>, @@ -1886,7 +1828,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { )); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, &format!("{} must be valid for ", labeled_user_string), sub, @@ -1904,7 +1845,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn report_sub_sup_conflict( &self, - region_scope_tree: ®ion::ScopeTree, var_origin: RegionVariableOrigin, sub_origin: SubregionOrigin<'tcx>, sub_region: Region<'tcx>, @@ -1915,7 +1855,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "first, the lifetime cannot outlive ", sup_region, @@ -1941,7 +1880,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if sub_expected == sup_expected && sub_found == sup_found { note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "...but the lifetime must also be valid for ", sub_region, @@ -1963,7 +1901,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "but, the lifetime must be valid for ", sub_region, diff --git a/src/librustc_infer/infer/error_reporting/note.rs b/src/librustc_infer/infer/error_reporting/note.rs index a4e51fe0b1c00..8fbb89da5af41 100644 --- a/src/librustc_infer/infer/error_reporting/note.rs +++ b/src/librustc_infer/infer/error_reporting/note.rs @@ -1,7 +1,6 @@ use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt}; use crate::infer::{self, InferCtxt, SubregionOrigin}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; -use rustc_middle::middle::region; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Region}; @@ -91,7 +90,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub(super) fn report_concrete_failure( &self, - region_scope_tree: ®ion::ScopeTree, origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, @@ -100,10 +98,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); let mut err = self.report_and_explain_type_error(trace, &terr); - note_and_explain_region(self.tcx, region_scope_tree, &mut err, "", sup, "..."); + note_and_explain_region(self.tcx, &mut err, "", sup, "..."); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "...does not necessarily outlive ", sub, @@ -121,7 +118,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "...the reference is valid for ", sub, @@ -129,7 +125,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "...but the borrowed content is only valid for ", sup, @@ -149,7 +144,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "...the borrowed pointer is valid for ", sub, @@ -157,7 +151,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, &format!("...but `{}` is only valid for ", var_name), sup, @@ -173,17 +166,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "lifetime of the source pointer does not outlive \ lifetime bound of the object type" ); + note_and_explain_region(self.tcx, &mut err, "object type is valid for ", sub, ""); note_and_explain_region( self.tcx, - region_scope_tree, - &mut err, - "object type is valid for ", - sub, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, &mut err, "source pointer is only valid for ", sup, @@ -201,22 +186,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.ty_to_string(ty) ); match *sub { - ty::ReStatic => note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "type must satisfy ", - sub, - "", - ), - _ => note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "type must outlive ", - sub, - "", - ), + ty::ReStatic => { + note_and_explain_region(self.tcx, &mut err, "type must satisfy ", sub, "") + } + _ => note_and_explain_region(self.tcx, &mut err, "type must outlive ", sub, ""), } err } @@ -225,7 +198,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "lifetime parameter instantiated with ", sup, @@ -233,7 +205,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "but lifetime parameter must outlive ", sub, @@ -251,7 +222,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); note_and_explain_region( self.tcx, - region_scope_tree, &mut err, "the return value is only valid for ", sup, @@ -267,22 +237,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "a value of type `{}` is borrowed for too long", self.ty_to_string(ty) ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the type is valid for ", - sub, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "but the borrow lasts for ", - sup, - "", - ); + note_and_explain_region(self.tcx, &mut err, "the type is valid for ", sub, ""); + note_and_explain_region(self.tcx, &mut err, "but the borrow lasts for ", sup, ""); err } infer::ReferenceOutlivesReferent(ty, span) => { @@ -293,17 +249,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "in type `{}`, reference has a longer lifetime than the data it references", self.ty_to_string(ty) ); + note_and_explain_region(self.tcx, &mut err, "the pointer is valid for ", sub, ""); note_and_explain_region( self.tcx, - region_scope_tree, - &mut err, - "the pointer is valid for ", - sub, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, &mut err, "but the referenced data is only valid for ", sup, @@ -328,7 +276,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub(super) fn report_placeholder_failure( &self, - region_scope_tree: ®ion::ScopeTree, placeholder_origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, @@ -340,7 +287,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.report_and_explain_type_error(trace, &terr) } - _ => self.report_concrete_failure(region_scope_tree, placeholder_origin, sub, sup), + _ => self.report_concrete_failure(placeholder_origin, sub, sup), } } } diff --git a/src/librustc_infer/infer/free_regions.rs b/src/librustc_infer/infer/free_regions.rs index e31c524c19710..d975038b010b9 100644 --- a/src/librustc_infer/infer/free_regions.rs +++ b/src/librustc_infer/infer/free_regions.rs @@ -5,7 +5,6 @@ use rustc_data_structures::transitive_relation::TransitiveRelation; use rustc_hir::def_id::DefId; -use rustc_middle::middle::region; use rustc_middle::ty::{self, Lift, Region, TyCtxt}; /// Combines a `region::ScopeTree` (which governs relationships between @@ -21,21 +20,13 @@ pub struct RegionRelations<'a, 'tcx> { /// The context used to fetch the region maps. pub context: DefId, - /// The region maps for the given context. - pub region_scope_tree: &'a region::ScopeTree, - /// Free-region relationships. pub free_regions: &'a FreeRegionMap<'tcx>, } impl<'a, 'tcx> RegionRelations<'a, 'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - context: DefId, - region_scope_tree: &'a region::ScopeTree, - free_regions: &'a FreeRegionMap<'tcx>, - ) -> Self { - Self { tcx, context, region_scope_tree, free_regions } + pub fn new(tcx: TyCtxt<'tcx>, context: DefId, free_regions: &'a FreeRegionMap<'tcx>) -> Self { + Self { tcx, context, free_regions } } pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> { diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index fdd0c5b2ff368..30af7d06744d7 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -20,7 +20,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; -use rustc_middle::middle::region; use rustc_middle::mir; use rustc_middle::mir::interpret::ConstEvalResult; use rustc_middle::traits::select; @@ -1213,7 +1212,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn resolve_regions_and_report_errors( &self, region_context: DefId, - region_map: ®ion::ScopeTree, outlives_env: &OutlivesEnvironment<'tcx>, mode: RegionckMode, ) { @@ -1233,12 +1231,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .into_infos_and_data() }; - let region_rels = &RegionRelations::new( - self.tcx, - region_context, - region_map, - outlives_env.free_region_map(), - ); + let region_rels = + &RegionRelations::new(self.tcx, region_context, outlives_env.free_region_map()); let (lexical_region_resolutions, errors) = lexical_region_resolve::resolve(region_rels, var_infos, data, mode); @@ -1252,7 +1246,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // 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(region_map, &errors); + self.report_region_errors(&errors); } } diff --git a/src/librustc_middle/middle/region.rs b/src/librustc_middle/middle/region.rs index f02d8fe8ad601..943a065a8b5e8 100644 --- a/src/librustc_middle/middle/region.rs +++ b/src/librustc_middle/middle/region.rs @@ -7,7 +7,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use crate::ty::{self, DefIdTree, TyCtxt}; +use crate::ty::TyCtxt; use rustc_hir as hir; use rustc_hir::Node; @@ -333,7 +333,7 @@ pub struct YieldData { pub source: hir::YieldSource, } -impl<'tcx> ScopeTree { +impl ScopeTree { pub fn record_scope_parent(&mut self, child: Scope, parent: Option<(Scope, ScopeDepth)>) { debug!("{:?}.parent = {:?}", child, parent); @@ -348,24 +348,6 @@ impl<'tcx> ScopeTree { } } - pub fn each_encl_scope(&self, mut e: E) - where - E: FnMut(Scope, Scope), - { - for (&child, &parent) in &self.parent_map { - e(child, parent.0) - } - } - - pub fn each_var_scope(&self, mut e: E) - where - E: FnMut(&hir::ItemLocalId, Scope), - { - for (child, &parent) in self.var_map.iter() { - e(child, parent) - } - } - pub fn opt_destruction_scope(&self, n: hir::ItemLocalId) -> Option { self.destruction_scopes.get(&n).cloned() } @@ -406,12 +388,6 @@ impl<'tcx> ScopeTree { self.parent_map.get(&id).cloned().map(|(p, _)| p) } - /// Returns the narrowest scope that encloses `id`, if any. - #[allow(dead_code)] // used in cfg - pub fn encl_scope(&self, id: Scope) -> Scope { - self.opt_encl_scope(id).unwrap() - } - /// Returns the lifetime of the local variable `var_id` pub fn var_scope(&self, var_id: hir::ItemLocalId) -> Scope { self.var_map @@ -448,17 +424,6 @@ impl<'tcx> ScopeTree { None } - /// Returns the lifetime of the variable `id`. - pub fn var_region(&self, id: hir::ItemLocalId) -> ty::RegionKind { - let scope = ty::ReScope(self.var_scope(id)); - debug!("var_region({:?}) = {:?}", id, scope); - scope - } - - pub fn scopes_intersect(&self, scope1: Scope, scope2: Scope) -> bool { - self.is_subscope_of(scope1, scope2) || self.is_subscope_of(scope2, scope1) - } - /// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and /// `false` otherwise. pub fn is_subscope_of(&self, subscope: Scope, superscope: Scope) -> bool { @@ -479,127 +444,6 @@ impl<'tcx> ScopeTree { true } - /// Returns the ID of the innermost containing body. - pub fn containing_body(&self, mut scope: Scope) -> Option { - loop { - if let ScopeData::CallSite = scope.data { - return Some(scope.item_local_id()); - } - - scope = self.opt_encl_scope(scope)?; - } - } - - /// Finds the nearest common ancestor of two scopes. That is, finds the - /// smallest scope which is greater than or equal to both `scope_a` and - /// `scope_b`. - pub fn nearest_common_ancestor(&self, scope_a: Scope, scope_b: Scope) -> Scope { - if scope_a == scope_b { - return scope_a; - } - - let mut a = scope_a; - let mut b = scope_b; - - // Get the depth of each scope's parent. If either scope has no parent, - // it must be the root, which means we can stop immediately because the - // root must be the nearest common ancestor. (In practice, this is - // moderately common.) - let (parent_a, parent_a_depth) = match self.parent_map.get(&a) { - Some(pd) => *pd, - None => return a, - }; - let (parent_b, parent_b_depth) = match self.parent_map.get(&b) { - Some(pd) => *pd, - None => return b, - }; - - if parent_a_depth > parent_b_depth { - // `a` is lower than `b`. Move `a` up until it's at the same depth - // as `b`. The first move up is trivial because we already found - // `parent_a` above; the loop does the remaining N-1 moves. - a = parent_a; - for _ in 0..(parent_a_depth - parent_b_depth - 1) { - a = self.parent_map.get(&a).unwrap().0; - } - } else if parent_b_depth > parent_a_depth { - // `b` is lower than `a`. - b = parent_b; - for _ in 0..(parent_b_depth - parent_a_depth - 1) { - b = self.parent_map.get(&b).unwrap().0; - } - } else { - // Both scopes are at the same depth, and we know they're not equal - // because that case was tested for at the top of this function. So - // we can trivially move them both up one level now. - assert!(parent_a_depth != 0); - a = parent_a; - b = parent_b; - } - - // Now both scopes are at the same level. We move upwards in lockstep - // until they match. In practice, this loop is almost always executed - // zero times because `a` is almost always a direct ancestor of `b` or - // vice versa. - while a != b { - a = self.parent_map.get(&a).unwrap().0; - b = self.parent_map.get(&b).unwrap().0; - } - - a - } - - /// Assuming that the provided region was defined within this `ScopeTree`, - /// returns the outermost `Scope` that the region outlives. - pub fn early_free_scope(&self, tcx: TyCtxt<'tcx>, br: &ty::EarlyBoundRegion) -> Scope { - let param_owner = tcx.parent(br.def_id).unwrap(); - - let param_owner_id = tcx.hir().as_local_hir_id(param_owner.expect_local()); - let scope = tcx - .hir() - .maybe_body_owned_by(param_owner_id) - .map(|body_id| tcx.hir().body(body_id).value.hir_id.local_id) - .unwrap_or_else(|| { - // The lifetime was defined on node that doesn't own a body, - // which in practice can only mean a trait or an impl, that - // is the parent of a method, and that is enforced below. - if Some(param_owner_id) != self.root_parent { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "free_scope: {:?} not recognized by the \ - region scope tree for {:?} / {:?}", - param_owner, - self.root_parent.map(|id| tcx.hir().local_def_id(id)), - self.root_body.map(|hir_id| hir_id.owner) - ), - ); - } - - // The trait/impl lifetime is in scope for the method's body. - self.root_body.unwrap().local_id - }); - - Scope { id: scope, data: ScopeData::CallSite } - } - - /// Assuming that the provided region was defined within this `ScopeTree`, - /// returns the outermost `Scope` that the region outlives. - pub fn free_scope(&self, tcx: TyCtxt<'tcx>, fr: &ty::FreeRegion) -> Scope { - let param_owner = match fr.bound_region { - ty::BoundRegion::BrNamed(def_id, _) => tcx.parent(def_id).unwrap(), - _ => fr.scope, - }; - - // Ensure that the named late-bound lifetimes were defined - // on the same function that they ended up being freed in. - assert_eq!(param_owner, fr.scope); - - let param_owner_id = tcx.hir().as_local_hir_id(param_owner.expect_local()); - let body_id = tcx.hir().body_owned_by(param_owner_id); - Scope { id: tcx.hir().body(body_id).value.hir_id.local_id, data: ScopeData::CallSite } - } - /// Checks whether the given scope contains a `yield`. If so, /// returns `Some((span, expr_count))` with the span of a yield we found and /// the number of expressions and patterns appearing before the `yield` in the body + 1. diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index ebc8021a3c577..e19fab89eabfe 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -162,10 +162,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let type_test_span = type_test.locations.span(&self.body); if let Some(lower_bound_region) = lower_bound_region { - let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); self.infcx .construct_generic_bound_failure( - region_scope_tree, type_test_span, None, type_test.generic_kind, @@ -194,12 +192,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => { - let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); unexpected_hidden_region_diagnostic( self.infcx.tcx, - Some(region_scope_tree), span, named_ty, named_region, diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index d14ae40b45a0b..484677ded249f 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -835,7 +835,6 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { if let Some(hidden_ty) = self.hidden_ty.take() { unexpected_hidden_region_diagnostic( self.tcx, - None, self.tcx.def_span(self.opaque_type_def_id), hidden_ty, r, diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 3daa9109aafe8..d8e99dc10af2a 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -28,7 +28,6 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::middle::region; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{ @@ -237,15 +236,12 @@ fn do_normalize_predicates<'tcx>( debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); - let region_scope_tree = region::ScopeTree::default(); - // We can use the `elaborated_env` here; the region code only // cares about declarations like `'a: 'b`. let outlives_env = OutlivesEnvironment::new(elaborated_env); infcx.resolve_regions_and_report_errors( region_context, - ®ion_scope_tree, &outlives_env, RegionckMode::default(), ); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 1b7fde69830f0..8fa901d8a984a 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -3,7 +3,6 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; use crate::astconv::AstConv; -use crate::middle::region; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::{FutureTraitLangItem, GeneratorTraitLangItem}; @@ -17,7 +16,6 @@ use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::ArgKind; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::Obligation; use std::cmp; use std::iter; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 594cdab852fda..24c319f26e71f 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -5,7 +5,6 @@ use rustc_errors::{struct_span_err, ErrorReported}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferOk, RegionckMode, TyCtxtInferExt}; use rustc_infer::traits::TraitEngineExt as _; -use rustc_middle::middle::region; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::{Subst, SubstsRef}; @@ -120,8 +119,6 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( return Err(ErrorReported); } - let region_scope_tree = region::ScopeTree::default(); - // NB. It seems a bit... suspicious to use an empty param-env // here. The correct thing, I imagine, would be // `OutlivesEnvironment::new(impl_param_env)`, which would @@ -134,7 +131,6 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( infcx.resolve_regions_and_report_errors( drop_impl_did.to_def_id(), - ®ion_scope_tree, &outlives_env, RegionckMode::default(), ); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index efa3cd9955b49..c5dd314dc6558 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -11,7 +11,6 @@ use rustc_hir::ItemKind; use rustc_infer::infer; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionckMode, TyCtxtInferExt}; -use rustc_middle::middle::region; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -293,11 +292,9 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef } // Finally, resolve all regions. - let region_scope_tree = region::ScopeTree::default(); let outlives_env = OutlivesEnvironment::new(param_env); infcx.resolve_regions_and_report_errors( impl_did.to_def_id(), - ®ion_scope_tree, &outlives_env, RegionckMode::default(), ); @@ -552,14 +549,8 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI } // Finally, resolve all regions. - let region_scope_tree = region::ScopeTree::default(); let outlives_env = OutlivesEnvironment::new(param_env); - infcx.resolve_regions_and_report_errors( - impl_did, - ®ion_scope_tree, - &outlives_env, - RegionckMode::default(), - ); + infcx.resolve_regions_and_report_errors(impl_did, &outlives_env, RegionckMode::default()); CoerceUnsizedInfo { custom_kind: kind } }) diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index d30dc1b7a475e..08404bea56138 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -73,7 +73,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt}; use rustc_infer::traits::specialization_graph::Node; -use rustc_middle::middle::region::ScopeTree; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable}; @@ -165,12 +164,7 @@ fn get_impl_substs<'tcx>( // Conservatively use an empty `ParamEnv`. let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); - infcx.resolve_regions_and_report_errors( - impl1_def_id, - &ScopeTree::default(), - &outlives_env, - RegionckMode::default(), - ); + infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default()); let impl2_substs = match infcx.fully_resolve(&impl2_substs) { Ok(s) => s, Err(_) => { From f9f3063cfaa792435ed88a92927bb2641388a7c6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 20 May 2020 18:58:41 +0100 Subject: [PATCH 165/695] Update tests --- .../ui/borrowck/issue-45983.migrate.stderr | 12 - src/test/ui/borrowck/issue-45983.nll.stderr | 21 -- src/test/ui/borrowck/issue-45983.rs | 16 +- ...und-fn-2.nll.stderr => issue-45983.stderr} | 4 +- src/test/ui/borrowck/issue-7573.nll.stderr | 14 - src/test/ui/borrowck/issue-7573.rs | 22 +- src/test/ui/borrowck/issue-7573.stderr | 14 +- .../ui/borrowck/regions-escape-bound-fn-2.rs | 7 +- .../borrowck/regions-escape-bound-fn-2.stderr | 12 +- .../regions-escape-bound-fn.nll.stderr | 12 - .../ui/borrowck/regions-escape-bound-fn.rs | 7 +- .../borrowck/regions-escape-bound-fn.stderr | 12 +- .../regions-escape-unboxed-closure.nll.stderr | 12 - .../regions-escape-unboxed-closure.rs | 5 +- .../regions-escape-unboxed-closure.stderr | 12 +- .../ui/c-variadic/variadic-ffi-4.nll.stderr | 123 -------- src/test/ui/c-variadic/variadic-ffi-4.rs | 26 +- src/test/ui/c-variadic/variadic-ffi-4.stderr | 275 ++++++------------ .../expect-region-supply-region-2.nll.stderr | 24 ++ .../expect-region-supply-region-2.rs | 24 ++ .../expect-region-supply-region-2.stderr | 55 ++++ .../expect-region-supply-region.nll.stderr | 44 --- .../expect-region-supply-region.rs | 27 +- .../expect-region-supply-region.stderr | 87 +----- src/test/ui/error-codes/E0490.nll.stderr | 28 ++ src/test/ui/error-codes/E0490.rs | 8 + src/test/ui/error-codes/E0490.stderr | 76 +++++ ...1-does-not-trigger-for-closures.nll.stderr | 11 - .../E0621-does-not-trigger-for-closures.rs | 6 +- ...E0621-does-not-trigger-for-closures.stderr | 31 +- .../ordinary-bounds-unrelated.stderr | 14 +- .../ordinary-bounds-unsuited.stderr | 14 +- .../regions-close-object-into-object-5.rs | 17 +- .../regions-close-object-into-object-5.stderr | 29 +- ...ons-close-over-type-parameter-1.nll.stderr | 4 +- .../regions-close-over-type-parameter-1.rs | 18 +- ...regions-close-over-type-parameter-1.stderr | 44 +-- .../regions/regions-escape-method.nll.stderr | 11 - src/test/ui/regions/regions-escape-method.rs | 2 +- .../ui/regions/regions-escape-method.stderr | 31 +- ...regions-escape-via-trait-or-not.nll.stderr | 11 - .../regions-escape-via-trait-or-not.rs | 2 +- .../regions-escape-via-trait-or-not.stderr | 31 +- .../regions/regions-infer-call-3.nll.stderr | 11 - src/test/ui/regions/regions-infer-call-3.rs | 2 +- .../ui/regions/regions-infer-call-3.stderr | 29 +- ...return-ref-to-upvar-issue-17403.nll.stderr | 13 - ...regions-return-ref-to-upvar-issue-17403.rs | 2 +- ...ons-return-ref-to-upvar-issue-17403.stderr | 29 +- src/test/ui/symbol-names/impl1.rs | 4 +- 50 files changed, 462 insertions(+), 883 deletions(-) delete mode 100644 src/test/ui/borrowck/issue-45983.migrate.stderr delete mode 100644 src/test/ui/borrowck/issue-45983.nll.stderr rename src/test/ui/borrowck/{regions-escape-bound-fn-2.nll.stderr => issue-45983.stderr} (81%) delete mode 100644 src/test/ui/borrowck/issue-7573.nll.stderr delete mode 100644 src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr delete mode 100644 src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr delete mode 100644 src/test/ui/c-variadic/variadic-ffi-4.nll.stderr create mode 100644 src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr create mode 100644 src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.rs create mode 100644 src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr delete mode 100644 src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr create mode 100644 src/test/ui/error-codes/E0490.nll.stderr create mode 100644 src/test/ui/error-codes/E0490.rs create mode 100644 src/test/ui/error-codes/E0490.stderr delete mode 100644 src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr delete mode 100644 src/test/ui/regions/regions-escape-method.nll.stderr delete mode 100644 src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr delete mode 100644 src/test/ui/regions/regions-infer-call-3.nll.stderr delete mode 100644 src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr diff --git a/src/test/ui/borrowck/issue-45983.migrate.stderr b/src/test/ui/borrowck/issue-45983.migrate.stderr deleted file mode 100644 index c1564cf07e68a..0000000000000 --- a/src/test/ui/borrowck/issue-45983.migrate.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error: borrowed data cannot be stored outside of its closure - --> $DIR/issue-45983.rs:20:27 - | -LL | let x = None; - | - borrowed data cannot be stored into here... -LL | give_any(|y| x = Some(y)); - | --- ^ cannot be stored outside of its closure - | | - | ...because it cannot outlive this closure - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr deleted file mode 100644 index 51bb4dee6762a..0000000000000 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0521]: borrowed data escapes outside of closure - --> $DIR/issue-45983.rs:20:18 - | -LL | let x = None; - | - `x` declared here, outside of the closure body -LL | give_any(|y| x = Some(y)); - | - ^^^^^^^^^^^ `y` escapes the closure body here - | | - | `y` is a reference that is only valid in the closure body - -error[E0594]: cannot assign to `x`, as it is not declared as mutable - --> $DIR/issue-45983.rs:20:18 - | -LL | let x = None; - | - help: consider changing this to be mutable: `mut x` -LL | give_any(|y| x = Some(y)); - | ^^^^^^^^^^^ cannot assign - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/issue-45983.rs b/src/test/ui/borrowck/issue-45983.rs index 3cd282077424b..6784f6f86a010 100644 --- a/src/test/ui/borrowck/issue-45983.rs +++ b/src/test/ui/borrowck/issue-45983.rs @@ -1,24 +1,12 @@ // As documented in Issue #45983, this test is evaluating the quality // of our diagnostics on erroneous code using higher-ranked closures. -// revisions: migrate nll - -// Since we are testing nll (and migration) explicitly as a separate -// revisions, don't worry about the --compare-mode=nll on this test. - -// ignore-compare-mode-nll -// ignore-compare-mode-polonius - -//[nll]compile-flags: -Z borrowck=mir - fn give_any FnOnce(&'r ())>(f: F) { f(&()); } fn main() { - let x = None; + let mut x = None; give_any(|y| x = Some(y)); - //[migrate]~^ ERROR borrowed data cannot be stored outside of its closure - //[nll]~^^ ERROR borrowed data escapes outside of closure - //[nll]~| ERROR cannot assign to `x`, as it is not declared as mutable + //~^ ERROR borrowed data escapes outside of closure } diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/issue-45983.stderr similarity index 81% rename from src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr rename to src/test/ui/borrowck/issue-45983.stderr index 68a0fe0b4f07b..efd414a2d44ff 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.stderr @@ -1,9 +1,9 @@ error[E0521]: borrowed data escapes outside of closure - --> $DIR/regions-escape-bound-fn-2.rs:8:18 + --> $DIR/issue-45983.rs:10:18 | LL | let mut x = None; | ----- `x` declared here, outside of the closure body -LL | with_int(|y| x = Some(y)); +LL | give_any(|y| x = Some(y)); | - ^^^^^^^^^^^ `y` escapes the closure body here | | | `y` is a reference that is only valid in the closure body diff --git a/src/test/ui/borrowck/issue-7573.nll.stderr b/src/test/ui/borrowck/issue-7573.nll.stderr deleted file mode 100644 index 20afecfe5de79..0000000000000 --- a/src/test/ui/borrowck/issue-7573.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0521]: borrowed data escapes outside of closure - --> $DIR/issue-7573.rs:21:9 - | -LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); - | ---------------- `lines_to_use` declared here, outside of the closure body -LL | -LL | let push_id = |installed_id: &CrateId| { - | ------------ `installed_id` is a reference that is only valid in the closure body -... -LL | lines_to_use.push(installed_id); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/issue-7573.rs b/src/test/ui/borrowck/issue-7573.rs index 20a6a5c92f149..7c07411533ff0 100644 --- a/src/test/ui/borrowck/issue-7573.rs +++ b/src/test/ui/borrowck/issue-7573.rs @@ -1,36 +1,34 @@ pub struct CrateId { local_path: String, - junk: String + junk: String, } impl CrateId { fn new(s: &str) -> CrateId { - CrateId { - local_path: s.to_string(), - junk: "wutevs".to_string() - } + CrateId { local_path: s.to_string(), junk: "wutevs".to_string() } } } pub fn remove_package_from_database() { let mut lines_to_use: Vec<&CrateId> = Vec::new(); - //~^ NOTE cannot infer an appropriate lifetime + //~^ NOTE `lines_to_use` declared here, outside of the closure body let push_id = |installed_id: &CrateId| { - //~^ NOTE borrowed data cannot outlive this closure - //~| NOTE ...so that variable is valid at time of its declaration + //~^ NOTE `installed_id` is a reference that is only valid in the closure body lines_to_use.push(installed_id); - //~^ ERROR borrowed data cannot be stored outside of its closure - //~| NOTE cannot be stored outside of its closure + //~^ ERROR borrowed data escapes outside of closure + //~| NOTE `installed_id` escapes the closure body here }; list_database(push_id); for l in &lines_to_use { println!("{}", l.local_path); } - } -pub fn list_database(mut f: F) where F: FnMut(&CrateId) { +pub fn list_database(mut f: F) +where + F: FnMut(&CrateId), +{ let stuff = ["foo", "bar"]; for l in &stuff { diff --git a/src/test/ui/borrowck/issue-7573.stderr b/src/test/ui/borrowck/issue-7573.stderr index 32b3ef72d8bda..815419db833e5 100644 --- a/src/test/ui/borrowck/issue-7573.stderr +++ b/src/test/ui/borrowck/issue-7573.stderr @@ -1,16 +1,14 @@ -error: borrowed data cannot be stored outside of its closure - --> $DIR/issue-7573.rs:21:27 +error[E0521]: borrowed data escapes outside of closure + --> $DIR/issue-7573.rs:17:9 | LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); - | - cannot infer an appropriate lifetime... + | ---------------- `lines_to_use` declared here, outside of the closure body LL | LL | let push_id = |installed_id: &CrateId| { - | ------- ------------------------ borrowed data cannot outlive this closure - | | - | ...so that variable is valid at time of its declaration -... + | ------------ `installed_id` is a reference that is only valid in the closure body +LL | LL | lines_to_use.push(installed_id); - | ^^^^^^^^^^^^ cannot be stored outside of its closure + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here error: aborting due to previous error diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.rs b/src/test/ui/borrowck/regions-escape-bound-fn-2.rs index cb423032b4610..0e98d98cf87b3 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn-2.rs +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.rs @@ -1,4 +1,7 @@ -fn with_int(f: F) where F: FnOnce(&isize) { +fn with_int(f: F) +where + F: FnOnce(&isize), +{ let x = 3; f(&x); } @@ -6,5 +9,5 @@ fn with_int(f: F) where F: FnOnce(&isize) { fn main() { let mut x = None; with_int(|y| x = Some(y)); - //~^ ERROR borrowed data cannot be stored outside of its closure + //~^ ERROR borrowed data escapes outside of closure } diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr index 4b37edafa1273..1dc60bb155452 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.stderr @@ -1,12 +1,12 @@ -error: borrowed data cannot be stored outside of its closure - --> $DIR/regions-escape-bound-fn-2.rs:8:27 +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-bound-fn-2.rs:11:18 | LL | let mut x = None; - | ----- borrowed data cannot be stored into here... + | ----- `x` declared here, outside of the closure body LL | with_int(|y| x = Some(y)); - | --- ^ cannot be stored outside of its closure - | | - | ...because it cannot outlive this closure + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr deleted file mode 100644 index d304de92c7e18..0000000000000 --- a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0521]: borrowed data escapes outside of closure - --> $DIR/regions-escape-bound-fn.rs:8:18 - | -LL | let mut x: Option<&isize> = None; - | ----- `x` declared here, outside of the closure body -LL | with_int(|y| x = Some(y)); - | - ^^^^^^^^^^^ `y` escapes the closure body here - | | - | `y` is a reference that is only valid in the closure body - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.rs b/src/test/ui/borrowck/regions-escape-bound-fn.rs index 772df3e6c5822..f896ae7bdada2 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn.rs +++ b/src/test/ui/borrowck/regions-escape-bound-fn.rs @@ -1,4 +1,7 @@ -fn with_int(f: F) where F: FnOnce(&isize) { +fn with_int(f: F) +where + F: FnOnce(&isize), +{ let x = 3; f(&x); } @@ -6,5 +9,5 @@ fn with_int(f: F) where F: FnOnce(&isize) { fn main() { let mut x: Option<&isize> = None; with_int(|y| x = Some(y)); - //~^ ERROR borrowed data cannot be stored outside of its closure + //~^ ERROR borrowed data escapes outside of closure } diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.stderr index 4973d5306f959..5c548ec2876a3 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn.stderr @@ -1,12 +1,12 @@ -error: borrowed data cannot be stored outside of its closure - --> $DIR/regions-escape-bound-fn.rs:8:27 +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-bound-fn.rs:11:18 | LL | let mut x: Option<&isize> = None; - | ----- borrowed data cannot be stored into here... + | ----- `x` declared here, outside of the closure body LL | with_int(|y| x = Some(y)); - | --- ^ cannot be stored outside of its closure - | | - | ...because it cannot outlive this closure + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr deleted file mode 100644 index d9931302f75fc..0000000000000 --- a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0521]: borrowed data escapes outside of closure - --> $DIR/regions-escape-unboxed-closure.rs:6:23 - | -LL | let mut x: Option<&isize> = None; - | ----- `x` declared here, outside of the closure body -LL | with_int(&mut |y| x = Some(y)); - | - ^^^^^^^^^^^ `y` escapes the closure body here - | | - | `y` is a reference that is only valid in the closure body - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.rs b/src/test/ui/borrowck/regions-escape-unboxed-closure.rs index d8bef927fd722..f01e47122d1e1 100644 --- a/src/test/ui/borrowck/regions-escape-unboxed-closure.rs +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.rs @@ -1,8 +1,7 @@ -fn with_int(f: &mut dyn FnMut(&isize)) { -} +fn with_int(f: &mut dyn FnMut(&isize)) {} fn main() { let mut x: Option<&isize> = None; with_int(&mut |y| x = Some(y)); - //~^ ERROR borrowed data cannot be stored outside of its closure + //~^ ERROR borrowed data escapes outside of closure } diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr index 047e290acae14..f2a49e70d2716 100644 --- a/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.stderr @@ -1,12 +1,12 @@ -error: borrowed data cannot be stored outside of its closure - --> $DIR/regions-escape-unboxed-closure.rs:6:32 +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-unboxed-closure.rs:5:23 | LL | let mut x: Option<&isize> = None; - | ----- borrowed data cannot be stored into here... + | ----- `x` declared here, outside of the closure body LL | with_int(&mut |y| x = Some(y)); - | --- ^ cannot be stored outside of its closure - | | - | ...because it cannot outlive this closure + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr deleted file mode 100644 index 89107e799bd22..0000000000000 --- a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr +++ /dev/null @@ -1,123 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:8:5 - | -LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `core::ffi::VaListImpl<'1>` - | | - | lifetime `'f` defined here -LL | ap - | ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:8:5 - | -LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `core::ffi::VaListImpl<'1>` - | | - | lifetime `'f` defined here -LL | ap - | ^^ returning this value requires that `'1` must outlive `'f` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:12:5 - | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - | -- has type `core::ffi::VaListImpl<'1>` -LL | ap - | ^^ returning this value requires that `'1` must outlive `'static` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:16:33 - | -LL | let _ = ap.with_copy(|ap| { ap }); - | --- ^^ returning this value requires that `'1` must outlive `'2` - | | | - | | return type of closure is core::ffi::VaList<'2, '_> - | has type `core::ffi::VaList<'1, '_>` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:20:5 - | -LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` - | | - | has type `&mut core::ffi::VaListImpl<'1>` -LL | *ap0 = ap1; - | ^^^^ assignment requires that `'1` must outlive `'2` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:20:5 - | -LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` - | | - | has type `&mut core::ffi::VaListImpl<'1>` -LL | *ap0 = ap1; - | ^^^^ assignment requires that `'2` must outlive `'1` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:24:5 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { - | --- ------- has type `core::ffi::VaListImpl<'2>` - | | - | has type `&mut core::ffi::VaListImpl<'1>` -LL | ap0 = &mut ap1; - | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:24:5 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { - | --- ------- has type `core::ffi::VaListImpl<'2>` - | | - | has type `&mut core::ffi::VaListImpl<'1>` -LL | ap0 = &mut ap1; - | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` - -error[E0384]: cannot assign to immutable argument `ap0` - --> $DIR/variadic-ffi-4.rs:24:5 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { - | --- help: make this binding mutable: `mut ap0` -LL | ap0 = &mut ap1; - | ^^^^^^^^^^^^^^ cannot assign to immutable argument - -error[E0597]: `ap1` does not live long enough - --> $DIR/variadic-ffi-4.rs:24:11 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { - | - let's call the lifetime of this reference `'3` -LL | ap0 = &mut ap1; - | ------^^^^^^^^ - | | | - | | borrowed value does not live long enough - | assignment requires that `ap1` is borrowed for `'3` -... -LL | } - | - `ap1` dropped here while still borrowed - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:31:12 - | -LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` - | | - | has type `&mut core::ffi::VaListImpl<'1>` -LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` - -error: lifetime may not live long enough - --> $DIR/variadic-ffi-4.rs:31:12 - | -LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` - | | - | has type `&mut core::ffi::VaListImpl<'1>` -LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ argument requires that `'2` must outlive `'1` - -error: aborting due to 12 previous errors - -Some errors have detailed explanations: E0384, E0597. -For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/c-variadic/variadic-ffi-4.rs b/src/test/ui/c-variadic/variadic-ffi-4.rs index a4d658cef1630..8064037942259 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.rs +++ b/src/test/ui/c-variadic/variadic-ffi-4.rs @@ -1,32 +1,38 @@ -#![crate_type="lib"] +#![crate_type = "lib"] #![no_std] #![feature(c_variadic)] use core::ffi::{VaList, VaListImpl}; pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - ap //~ ERROR: mismatched types + ap + //~^ ERROR: lifetime may not live long enough + //~| ERROR: lifetime may not live long enough } pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - ap //~ ERROR: mismatched types + ap //~ ERROR: lifetime may not live long enough } pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { - let _ = ap.with_copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime + let _ = ap.with_copy(|ap| ap); //~ ERROR: lifetime may not live long enough } pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - *ap0 = ap1; //~ ERROR: mismatched types + *ap0 = ap1; + //~^ ERROR: lifetime may not live long enough + //~| ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { +pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { ap0 = &mut ap1; - //~^ ERROR: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long - //~| ERROR: mismatched types - //~| ERROR: cannot infer an appropriate lifetime + //~^ ERROR: `ap1` does not live long enough + //~| ERROR: lifetime may not live long enough + //~| ERROR: lifetime may not live long enough } pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - *ap0 = ap1.clone(); //~ ERROR: mismatched types + *ap0 = ap1.clone(); + //~^ ERROR: lifetime may not live long enough + //~| ERROR: lifetime may not live long enough } diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index cd4cd8b198de8..65623501569e1 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -1,217 +1,114 @@ -error[E0308]: mismatched types +error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { + | -- -- has type `core::ffi::VaListImpl<'1>` + | | + | lifetime `'f` defined here LL | ap - | ^^ lifetime mismatch - | - = note: expected struct `core::ffi::VaListImpl<'f>` - found struct `core::ffi::VaListImpl<'_>` -note: the scope of call-site for function at 7:78... - --> $DIR/variadic-ffi-4.rs:7:78 - | -LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | ______________________________________________________________________________^ -LL | | ap -LL | | } - | |_^ -note: ...does not necessarily outlive the lifetime `'f` as defined on the function body at 7:37 - --> $DIR/variadic-ffi-4.rs:7:37 + | ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f` + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:8:5 | LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | ^^ + | -- -- has type `core::ffi::VaListImpl<'1>` + | | + | lifetime `'f` defined here +LL | ap + | ^^ returning this value requires that `'1` must outlive `'f` -error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:12:5 +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:14:5 | +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { + | -- has type `core::ffi::VaListImpl<'1>` LL | ap - | ^^ lifetime mismatch - | - = note: expected struct `core::ffi::VaListImpl<'static>` - found struct `core::ffi::VaListImpl<'_>` -note: the scope of call-site for function at 11:79... - --> $DIR/variadic-ffi-4.rs:11:79 - | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - | _______________________________________________________________________________^ -LL | | ap -LL | | } - | |_^ - = note: ...does not necessarily outlive the static lifetime + | ^^ returning this value requires that `'1` must outlive `'static` -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/variadic-ffi-4.rs:16:33 - | -LL | let _ = ap.with_copy(|ap| { ap }); - | ^^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 16:26... - --> $DIR/variadic-ffi-4.rs:16:26 - | -LL | let _ = ap.with_copy(|ap| { ap }); - | ^^^^^^^^^^^ -note: ...so that the expression is assignable - --> $DIR/variadic-ffi-4.rs:16:33 - | -LL | let _ = ap.with_copy(|ap| { ap }); - | ^^ - = note: expected `core::ffi::VaList<'_, '_>` - found `core::ffi::VaList<'_, '_>` -note: but, the lifetime must be valid for the method call at 16:13... - --> $DIR/variadic-ffi-4.rs:16:13 - | -LL | let _ = ap.with_copy(|ap| { ap }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...so type `core::ffi::VaList<'_, '_>` of expression is valid during the expression - --> $DIR/variadic-ffi-4.rs:16:13 - | -LL | let _ = ap.with_copy(|ap| { ap }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:18:31 + | +LL | let _ = ap.with_copy(|ap| ap); + | --- ^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of closure is core::ffi::VaList<'2, '_> + | has type `core::ffi::VaList<'1, '_>` -error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:20:12 +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:22:5 | +LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'2>` + | | + | has type `&mut core::ffi::VaListImpl<'1>` LL | *ap0 = ap1; - | ^^^ lifetime mismatch - | - = note: expected struct `core::ffi::VaListImpl<'_>` - found struct `core::ffi::VaListImpl<'_>` -note: the scope of call-site for function at 19:87... - --> $DIR/variadic-ffi-4.rs:19:87 - | -LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | _______________________________________________________________________________________^ -LL | | *ap0 = ap1; -LL | | } - | |_^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 19:1 - --> $DIR/variadic-ffi-4.rs:19:1 - | -LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { -LL | | *ap0 = ap1; -LL | | } - | |_^ + | ^^^^ assignment requires that `'1` must outlive `'2` -error[E0490]: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long - --> $DIR/variadic-ffi-4.rs:24:11 +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:22:5 | -LL | ap0 = &mut ap1; - | ^^^^^^^^ - | -note: the type is valid for the anonymous lifetime #1 defined on the function body at 23:1 - --> $DIR/variadic-ffi-4.rs:23:1 - | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { -LL | | ap0 = &mut ap1; -LL | | -LL | | -LL | | -LL | | } - | |_^ -note: but the borrow lasts for the scope of call-site for function at 23:83 - --> $DIR/variadic-ffi-4.rs:23:83 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { - | ___________________________________________________________________________________^ -LL | | ap0 = &mut ap1; -LL | | -LL | | -LL | | -LL | | } - | |_^ +LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'2>` + | | + | has type `&mut core::ffi::VaListImpl<'1>` +LL | *ap0 = ap1; + | ^^^^ assignment requires that `'2` must outlive `'1` -error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:24:11 +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:28:5 | +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'2>` + | | + | has type `&mut core::ffi::VaListImpl<'1>` LL | ap0 = &mut ap1; - | ^^^^^^^^ lifetime mismatch - | - = note: expected mutable reference `&mut core::ffi::VaListImpl<'_>` - found mutable reference `&mut core::ffi::VaListImpl<'_>` -note: the scope of call-site for function at 23:83... - --> $DIR/variadic-ffi-4.rs:23:83 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { - | ___________________________________________________________________________________^ -LL | | ap0 = &mut ap1; -LL | | -LL | | -LL | | -LL | | } - | |_^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 23:1 - --> $DIR/variadic-ffi-4.rs:23:1 - | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { -LL | | ap0 = &mut ap1; -LL | | -LL | | -LL | | -LL | | } - | |_^ + | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements - --> $DIR/variadic-ffi-4.rs:24:11 +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:28:5 | +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'2>` + | | + | has type `&mut core::ffi::VaListImpl<'1>` LL | ap0 = &mut ap1; - | ^^^^^^^^ - | -note: first, the lifetime cannot outlive the scope of call-site for function at 23:83... - --> $DIR/variadic-ffi-4.rs:23:83 - | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { - | ___________________________________________________________________________________^ -LL | | ap0 = &mut ap1; -LL | | -LL | | -LL | | -LL | | } - | |_^ -note: ...so that the type `core::ffi::VaListImpl<'_>` is not borrowed for too long - --> $DIR/variadic-ffi-4.rs:24:11 - | -LL | ap0 = &mut ap1; - | ^^^^^^^^ -note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 23:1... - --> $DIR/variadic-ffi-4.rs:23:1 - | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { -LL | | ap0 = &mut ap1; -LL | | -LL | | -LL | | -LL | | } - | |_^ -note: ...so that reference does not outlive borrowed content - --> $DIR/variadic-ffi-4.rs:24:11 + | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` + +error[E0597]: `ap1` does not live long enough + --> $DIR/variadic-ffi-4.rs:28:11 | +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | - let's call the lifetime of this reference `'3` LL | ap0 = &mut ap1; - | ^^^^^^^^ + | ------^^^^^^^^ + | | | + | | borrowed value does not live long enough + | assignment requires that `ap1` is borrowed for `'3` +... +LL | } + | - `ap1` dropped here while still borrowed -error[E0308]: mismatched types - --> $DIR/variadic-ffi-4.rs:31:12 +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:35:12 | +LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'2>` + | | + | has type `&mut core::ffi::VaListImpl<'1>` LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ lifetime mismatch - | - = note: expected struct `core::ffi::VaListImpl<'_>` - found struct `core::ffi::VaListImpl<'_>` -note: the scope of call-site for function at 30:87... - --> $DIR/variadic-ffi-4.rs:30:87 - | -LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | _______________________________________________________________________________________^ -LL | | *ap0 = ap1.clone(); -LL | | } - | |_^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 30:1 - --> $DIR/variadic-ffi-4.rs:30:1 + | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:35:12 | -LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { -LL | | *ap0 = ap1.clone(); -LL | | } - | |_^ +LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'2>` + | | + | has type `&mut core::ffi::VaListImpl<'1>` +LL | *ap0 = ap1.clone(); + | ^^^^^^^^^^^ argument requires that `'2` must outlive `'1` -error: aborting due to 8 previous errors +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0308, E0495. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr new file mode 100644 index 0000000000000..52bca8dd63e1f --- /dev/null +++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr @@ -0,0 +1,24 @@ +error: lifetime may not live long enough + --> $DIR/expect-region-supply-region-2.rs:14:30 + | +LL | fn expect_bound_supply_named<'x>() { + | -- lifetime `'x` defined here +... +LL | closure_expecting_bound(|x: &'x u32| { + | ^ - let's call the lifetime of this reference `'1` + | | + | requires that `'1` must outlive `'x` + +error: lifetime may not live long enough + --> $DIR/expect-region-supply-region-2.rs:14:30 + | +LL | fn expect_bound_supply_named<'x>() { + | -- lifetime `'x` defined here +... +LL | closure_expecting_bound(|x: &'x u32| { + | ^ requires that `'x` must outlive `'static` + | + = help: consider replacing `'x` with `'static` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.rs b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.rs new file mode 100644 index 0000000000000..7405b1a1e3a28 --- /dev/null +++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.rs @@ -0,0 +1,24 @@ +#![allow(warnings)] + +fn closure_expecting_bound(_: F) +where + F: FnOnce(&u32), +{ +} + +fn expect_bound_supply_named<'x>() { + let mut f: Option<&u32> = None; + + // Here we give a type annotation that `x` should be free. We get + // an error because of that. + closure_expecting_bound(|x: &'x u32| { + //~^ ERROR mismatched types + //~| ERROR mismatched types + + // Borrowck doesn't get a chance to run, but if it did it should error + // here. + f = Some(x); + }); +} + +fn main() {} diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr new file mode 100644 index 0000000000000..7f527904a69e5 --- /dev/null +++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/expect-region-supply-region-2.rs:14:33 + | +LL | closure_expecting_bound(|x: &'x u32| { + | ^^^^^^^ lifetime mismatch + | + = note: expected reference `&u32` + found reference `&'x u32` +note: the anonymous lifetime #2 defined on the body at 14:29... + --> $DIR/expect-region-supply-region-2.rs:14:29 + | +LL | closure_expecting_bound(|x: &'x u32| { + | _____________________________^ +LL | | +LL | | +LL | | +... | +LL | | f = Some(x); +LL | | }); + | |_____^ +note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 9:30 + --> $DIR/expect-region-supply-region-2.rs:9:30 + | +LL | fn expect_bound_supply_named<'x>() { + | ^^ + +error[E0308]: mismatched types + --> $DIR/expect-region-supply-region-2.rs:14:33 + | +LL | closure_expecting_bound(|x: &'x u32| { + | ^^^^^^^ lifetime mismatch + | + = note: expected reference `&u32` + found reference `&'x u32` +note: the lifetime `'x` as defined on the function body at 9:30... + --> $DIR/expect-region-supply-region-2.rs:9:30 + | +LL | fn expect_bound_supply_named<'x>() { + | ^^ +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 14:29 + --> $DIR/expect-region-supply-region-2.rs:14:29 + | +LL | closure_expecting_bound(|x: &'x u32| { + | _____________________________^ +LL | | +LL | | +LL | | +... | +LL | | f = Some(x); +LL | | }); + | |_____^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr deleted file mode 100644 index d7d716ed4cb0a..0000000000000 --- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.nll.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error[E0521]: borrowed data escapes outside of closure - --> $DIR/expect-region-supply-region.rs:18:9 - | -LL | let mut f: Option<&u32> = None; - | ----- `f` declared here, outside of the closure body -LL | closure_expecting_bound(|x| { - | - `x` is a reference that is only valid in the closure body -LL | f = Some(x); - | ^^^^^^^^^^^ `x` escapes the closure body here - -error[E0521]: borrowed data escapes outside of closure - --> $DIR/expect-region-supply-region.rs:28:9 - | -LL | let mut f: Option<&u32> = None; - | ----- `f` declared here, outside of the closure body -LL | closure_expecting_bound(|x: &u32| { - | - `x` is a reference that is only valid in the closure body -LL | f = Some(x); - | ^^^^^^^^^^^ `x` escapes the closure body here - -error: lifetime may not live long enough - --> $DIR/expect-region-supply-region.rs:37:30 - | -LL | fn expect_bound_supply_named<'x>() { - | -- lifetime `'x` defined here -... -LL | closure_expecting_bound(|x: &'x u32| { - | ^ - let's call the lifetime of this reference `'1` - | | - | requires that `'1` must outlive `'x` - -error: lifetime may not live long enough - --> $DIR/expect-region-supply-region.rs:37:30 - | -LL | fn expect_bound_supply_named<'x>() { - | -- lifetime `'x` defined here -... -LL | closure_expecting_bound(|x: &'x u32| { - | ^ requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` - -error: aborting due to 4 previous errors - diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.rs b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.rs index 28a6ab77a915e..55c6aa795c26a 100644 --- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.rs +++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.rs @@ -1,12 +1,14 @@ #![allow(warnings)] fn closure_expecting_bound(_: F) - where F: FnOnce(&u32) +where + F: FnOnce(&u32), { } fn closure_expecting_free<'a, F>(_: F) - where F: FnOnce(&'a u32) +where + F: FnOnce(&'a u32), { } @@ -15,7 +17,7 @@ fn expect_bound_supply_nothing() { // it to escape into `f`: let mut f: Option<&u32> = None; closure_expecting_bound(|x| { - f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure + f = Some(x); //~ ERROR borrowed data escapes outside of closure }); } @@ -25,22 +27,7 @@ fn expect_bound_supply_bound() { // closure: let mut f: Option<&u32> = None; closure_expecting_bound(|x: &u32| { - f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure - }); -} - -fn expect_bound_supply_named<'x>() { - let mut f: Option<&u32> = None; - - // Here we give a type annotation that `x` should be free. We get - // an error because of that. - closure_expecting_bound(|x: &'x u32| { - //~^ ERROR mismatched types - //~| ERROR mismatched types - - // And we still cannot let `x` escape into `f`. - f = Some(x); - //~^ ERROR borrowed data cannot be stored outside of its closure + f = Some(x); //~ ERROR borrowed data escapes outside of closure }); } @@ -67,4 +54,4 @@ fn expect_free_supply_named<'x>() { closure_expecting_free(|x: &'x u32| f = Some(x)); // OK } -fn main() { } +fn main() {} diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr index eb860f9aef243..213071abfffc3 100644 --- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr +++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region.stderr @@ -1,87 +1,22 @@ -error: borrowed data cannot be stored outside of its closure - --> $DIR/expect-region-supply-region.rs:18:18 +error[E0521]: borrowed data escapes outside of closure + --> $DIR/expect-region-supply-region.rs:20:9 | LL | let mut f: Option<&u32> = None; - | ----- borrowed data cannot be stored into here... + | ----- `f` declared here, outside of the closure body LL | closure_expecting_bound(|x| { - | --- ...because it cannot outlive this closure + | - `x` is a reference that is only valid in the closure body LL | f = Some(x); - | ^ cannot be stored outside of its closure + | ^^^^^^^^^^^ `x` escapes the closure body here -error: borrowed data cannot be stored outside of its closure - --> $DIR/expect-region-supply-region.rs:28:18 +error[E0521]: borrowed data escapes outside of closure + --> $DIR/expect-region-supply-region.rs:30:9 | LL | let mut f: Option<&u32> = None; - | ----- borrowed data cannot be stored into here... + | ----- `f` declared here, outside of the closure body LL | closure_expecting_bound(|x: &u32| { - | --------- ...because it cannot outlive this closure + | - `x` is a reference that is only valid in the closure body LL | f = Some(x); - | ^ cannot be stored outside of its closure + | ^^^^^^^^^^^ `x` escapes the closure body here -error[E0308]: mismatched types - --> $DIR/expect-region-supply-region.rs:37:33 - | -LL | closure_expecting_bound(|x: &'x u32| { - | ^^^^^^^ lifetime mismatch - | - = note: expected reference `&u32` - found reference `&'x u32` -note: the anonymous lifetime #2 defined on the body at 37:29... - --> $DIR/expect-region-supply-region.rs:37:29 - | -LL | closure_expecting_bound(|x: &'x u32| { - | _____________________________^ -LL | | -LL | | -LL | | -... | -LL | | -LL | | }); - | |_____^ -note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 32:30 - --> $DIR/expect-region-supply-region.rs:32:30 - | -LL | fn expect_bound_supply_named<'x>() { - | ^^ - -error[E0308]: mismatched types - --> $DIR/expect-region-supply-region.rs:37:33 - | -LL | closure_expecting_bound(|x: &'x u32| { - | ^^^^^^^ lifetime mismatch - | - = note: expected reference `&u32` - found reference `&'x u32` -note: the lifetime `'x` as defined on the function body at 32:30... - --> $DIR/expect-region-supply-region.rs:32:30 - | -LL | fn expect_bound_supply_named<'x>() { - | ^^ -note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 37:29 - --> $DIR/expect-region-supply-region.rs:37:29 - | -LL | closure_expecting_bound(|x: &'x u32| { - | _____________________________^ -LL | | -LL | | -LL | | -... | -LL | | -LL | | }); - | |_____^ - -error: borrowed data cannot be stored outside of its closure - --> $DIR/expect-region-supply-region.rs:42:18 - | -LL | let mut f: Option<&u32> = None; - | ----- borrowed data cannot be stored into here... -... -LL | closure_expecting_bound(|x: &'x u32| { - | ------------ ...because it cannot outlive this closure -... -LL | f = Some(x); - | ^ cannot be stored outside of its closure - -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/error-codes/E0490.nll.stderr b/src/test/ui/error-codes/E0490.nll.stderr new file mode 100644 index 0000000000000..a1c33bbcd5f75 --- /dev/null +++ b/src/test/ui/error-codes/E0490.nll.stderr @@ -0,0 +1,28 @@ +error: lifetime may not live long enough + --> $DIR/E0490.rs:2:12 + | +LL | fn f<'a, 'b>(y: &'b ()) { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let x: &'a _ = &y; + | ^^^^^ type annotation requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +error[E0597]: `y` does not live long enough + --> $DIR/E0490.rs:2:20 + | +LL | fn f<'a, 'b>(y: &'b ()) { + | -- lifetime `'a` defined here +LL | let x: &'a _ = &y; + | ----- ^^ borrowed value does not live long enough + | | + | type annotation requires that `y` is borrowed for `'a` +... +LL | } + | - `y` dropped here while still borrowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/error-codes/E0490.rs b/src/test/ui/error-codes/E0490.rs new file mode 100644 index 0000000000000..36bafa2bd868c --- /dev/null +++ b/src/test/ui/error-codes/E0490.rs @@ -0,0 +1,8 @@ +fn f<'a, 'b>(y: &'b ()) { + let x: &'a _ = &y; + //~^ E0490 + //~| E0495 + //~| E0495 +} + +fn main() {} diff --git a/src/test/ui/error-codes/E0490.stderr b/src/test/ui/error-codes/E0490.stderr new file mode 100644 index 0000000000000..03fce213605e3 --- /dev/null +++ b/src/test/ui/error-codes/E0490.stderr @@ -0,0 +1,76 @@ +error[E0490]: a value of type `&'b ()` is borrowed for too long + --> $DIR/E0490.rs:2:20 + | +LL | let x: &'a _ = &y; + | ^^ + | +note: the type is valid for the lifetime `'a` as defined on the function body at 1:6 + --> $DIR/E0490.rs:1:6 + | +LL | fn f<'a, 'b>(y: &'b ()) { + | ^^ +note: but the borrow lasts for the lifetime `'b` as defined on the function body at 1:10 + --> $DIR/E0490.rs:1:10 + | +LL | fn f<'a, 'b>(y: &'b ()) { + | ^^ + +error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements + --> $DIR/E0490.rs:2:20 + | +LL | let x: &'a _ = &y; + | ^^ + | +note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 1:10... + --> $DIR/E0490.rs:1:10 + | +LL | fn f<'a, 'b>(y: &'b ()) { + | ^^ +note: ...so that the type `&'b ()` is not borrowed for too long + --> $DIR/E0490.rs:2:20 + | +LL | let x: &'a _ = &y; + | ^^ +note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6... + --> $DIR/E0490.rs:1:6 + | +LL | fn f<'a, 'b>(y: &'b ()) { + | ^^ +note: ...so that reference does not outlive borrowed content + --> $DIR/E0490.rs:2:20 + | +LL | let x: &'a _ = &y; + | ^^ + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/E0490.rs:2:20 + | +LL | let x: &'a _ = &y; + | ^^ + | +note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 1:10... + --> $DIR/E0490.rs:1:10 + | +LL | fn f<'a, 'b>(y: &'b ()) { + | ^^ +note: ...so that the expression is assignable + --> $DIR/E0490.rs:2:20 + | +LL | let x: &'a _ = &y; + | ^^ + = note: expected `&'a &()` + found `&'a &'b ()` +note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6... + --> $DIR/E0490.rs:1:6 + | +LL | fn f<'a, 'b>(y: &'b ()) { + | ^^ +note: ...so that the reference type `&'a &()` does not outlive the data it points at + --> $DIR/E0490.rs:2:12 + | +LL | let x: &'a _ = &y; + | ^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr deleted file mode 100644 index 5140d1a9a7add..0000000000000 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/E0621-does-not-trigger-for-closures.rs:15:45 - | -LL | invoke(&x, |a, b| if a > b { a } else { b }); - | -- ^ returning this value requires that `'1` must outlive `'2` - | || - | |return type of closure is &'2 i32 - | has type `&'1 i32` - -error: aborting due to previous error - diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.rs b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.rs index c58744d386ca5..44f174c0fb76f 100644 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.rs +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.rs @@ -1,9 +1,7 @@ -// Test that we give the generic E0495 when one of the free regions is +// Test that we give the generic error when one of the free regions is // bound in a closure (rather than suggesting a change to the signature // of the closure, which is not specified in `foo` but rather in `invoke`). -// FIXME - This might be better as a UI test, but the finer details -// of the error seem to vary on different machines. fn invoke<'a, F>(x: &'a i32, f: F) -> &'a i32 where F: FnOnce(&'a i32, &i32) -> &'a i32 { @@ -12,7 +10,7 @@ where F: FnOnce(&'a i32, &i32) -> &'a i32 } fn foo<'a>(x: &'a i32) { - invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 + invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR lifetime may not live long enough } fn main() {} diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr index feca7f10b706b..b9edeb8346bdc 100644 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.stderr @@ -1,30 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements - --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5 +error: lifetime may not live long enough + --> $DIR/E0621-does-not-trigger-for-closures.rs:13:45 | LL | invoke(&x, |a, b| if a > b { a } else { b }); - | ^^^^^^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:16... - --> $DIR/E0621-does-not-trigger-for-closures.rs:15:16 - | -LL | invoke(&x, |a, b| if a > b { a } else { b }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...so that reference does not outlive borrowed content - --> $DIR/E0621-does-not-trigger-for-closures.rs:15:45 - | -LL | invoke(&x, |a, b| if a > b { a } else { b }); - | ^ -note: but, the lifetime must be valid for the call at 15:5... - --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5 - | -LL | invoke(&x, |a, b| if a > b { a } else { b }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...so type `&i32` of expression is valid during the expression - --> $DIR/E0621-does-not-trigger-for-closures.rs:15:5 - | -LL | invoke(&x, |a, b| if a > b { a } else { b }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 i32 + | has type `&'1 i32` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr index cd2d46ac18218..b42ff1486f0a8 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -4,17 +4,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | ^^^^^^^^^^^^^^^^^^ | -note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 23:1 - --> $DIR/ordinary-bounds-unrelated.rs:23:1 +note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body + --> $DIR/ordinary-bounds-unrelated.rs:18:74 | -LL | / { -LL | | // Hidden type `Ordinary<'0>` with constraints: -LL | | // -LL | | // ``` -... | -LL | | if condition() { a } else { b } -LL | | } - | |_^ +LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr index 59ce93fa78b6b..254643c406cae 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -4,17 +4,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | ^^^^^^^^^^^^^^^^^^ | -note: hidden type `Ordinary<'_>` captures the scope of call-site for function at 22:1 - --> $DIR/ordinary-bounds-unsuited.rs:22:1 +note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body + --> $DIR/ordinary-bounds-unsuited.rs:20:62 | -LL | / { -LL | | // We return a value: -LL | | // -LL | | // ``` -... | -LL | | if condition() { a } else { b } -LL | | } - | |_^ +LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-5.rs b/src/test/ui/regions/regions-close-object-into-object-5.rs index 2921a2bb398c3..ff35b9ada45cd 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.rs +++ b/src/test/ui/regions/regions-close-object-into-object-5.rs @@ -6,22 +6,21 @@ trait A fn get(&self) -> T { panic!() } } -struct B<'a, T:'a>(&'a (A+'a)); +struct B<'a, T: 'a>(&'a (A + 'a)); trait X { fn foo(&self) {} } impl<'a, T> X for B<'a, T> {} -fn f<'a, T, U>(v: Box+'static>) -> Box { +fn f<'a, T, U>(v: Box + 'static>) -> Box { // oh dear! box B(&*v) as Box - //~^ ERROR the parameter type `T` may not live long enough - //~| ERROR the parameter type `T` may not live long enough - //~| ERROR the parameter type `T` may not live long enough - //~| ERROR the parameter type `T` may not live long enough - //~| ERROR the parameter type `T` may not live long enough - //~| ERROR the parameter type `T` may not live long enough - //~| ERROR the parameter type `T` may not live long enough + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-5.stderr b/src/test/ui/regions/regions-close-object-into-object-5.stderr index 14727000b2c24..2bcdcd1864e2f 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-5.stderr @@ -1,7 +1,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:5 | -LL | fn f<'a, T, U>(v: Box+'static>) -> Box { +LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box @@ -13,25 +13,10 @@ note: ...so that the type `B<'_, T>` will meet its required lifetime bounds LL | box B(&*v) as Box | ^^^^^^^^^^ -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:5 - | -LL | fn f<'a, T, U>(v: Box+'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that it can be closed over into an object - --> $DIR/regions-close-object-into-object-5.rs:17:5 - | -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^ - error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:9 | -LL | fn f<'a, T, U>(v: Box+'static>) -> Box { +LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box @@ -46,7 +31,7 @@ LL | box B(&*v) as Box error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:9 | -LL | fn f<'a, T, U>(v: Box+'static>) -> Box { +LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box @@ -61,7 +46,7 @@ LL | box B(&*v) as Box error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 | -LL | fn f<'a, T, U>(v: Box+'static>) -> Box { +LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box @@ -76,7 +61,7 @@ LL | box B(&*v) as Box error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 | -LL | fn f<'a, T, U>(v: Box+'static>) -> Box { +LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box @@ -91,7 +76,7 @@ LL | box B(&*v) as Box error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 | -LL | fn f<'a, T, U>(v: Box+'static>) -> Box { +LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box @@ -103,6 +88,6 @@ note: ...so that the type `(dyn A + 'static)` is not borrowed for too long LL | box B(&*v) as Box | ^^^ -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr index 7d3d51bdb437e..3101d815881b1 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr @@ -1,5 +1,5 @@ error[E0310]: the parameter type `A` may not live long enough - --> $DIR/regions-close-over-type-parameter-1.rs:10:5 + --> $DIR/regions-close-over-type-parameter-1.rs:12:5 | LL | box v as Box | ^^^^^ @@ -7,7 +7,7 @@ LL | box v as Box = help: consider adding an explicit lifetime bound `A: 'static`... error[E0309]: the parameter type `A` may not live long enough - --> $DIR/regions-close-over-type-parameter-1.rs:20:5 + --> $DIR/regions-close-over-type-parameter-1.rs:21:5 | LL | box v as Box | ^^^^^ diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.rs b/src/test/ui/regions/regions-close-over-type-parameter-1.rs index 6a9aa66a446c3..6e708a5f70fbd 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.rs +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.rs @@ -4,22 +4,22 @@ // an object. This should yield errors unless `A` (and the object) // both have suitable bounds. -trait SomeTrait { fn get(&self) -> isize; } +trait SomeTrait { + fn get(&self) -> isize; +} -fn make_object1(v: A) -> Box { +fn make_object1(v: A) -> Box { box v as Box - //~^ ERROR the parameter type `A` may not live long enough - //~| ERROR the parameter type `A` may not live long enough + //~^ ERROR the parameter type `A` may not live long enough } -fn make_object2<'a,A:SomeTrait+'a>(v: A) -> Box { +fn make_object2<'a, A: SomeTrait + 'a>(v: A) -> Box { box v as Box } -fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { +fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { box v as Box - //~^ ERROR the parameter type `A` may not live long enough - //~| ERROR the parameter type `A` may not live long enough + //~^ ERROR the parameter type `A` may not live long enough } -fn main() { } +fn main() {} diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr index ed9a604e717dd..a7509cb608c6b 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr @@ -1,60 +1,32 @@ error[E0310]: the parameter type `A` may not live long enough - --> $DIR/regions-close-over-type-parameter-1.rs:10:5 + --> $DIR/regions-close-over-type-parameter-1.rs:12:5 | -LL | fn make_object1(v: A) -> Box { +LL | fn make_object1(v: A) -> Box { | -- help: consider adding an explicit lifetime bound...: `A: 'static +` LL | box v as Box | ^^^^^ | note: ...so that the type `A` will meet its required lifetime bounds - --> $DIR/regions-close-over-type-parameter-1.rs:10:5 + --> $DIR/regions-close-over-type-parameter-1.rs:12:5 | LL | box v as Box | ^^^^^ -error[E0310]: the parameter type `A` may not live long enough - --> $DIR/regions-close-over-type-parameter-1.rs:10:5 - | -LL | fn make_object1(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound...: `A: 'static +` -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that it can be closed over into an object - --> $DIR/regions-close-over-type-parameter-1.rs:10:5 - | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0309]: the parameter type `A` may not live long enough - --> $DIR/regions-close-over-type-parameter-1.rs:20:5 + --> $DIR/regions-close-over-type-parameter-1.rs:21:5 | -LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound...: `A: 'b +` +LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { + | -- help: consider adding an explicit lifetime bound...: `A: 'b +` LL | box v as Box | ^^^^^ | note: ...so that the type `A` will meet its required lifetime bounds - --> $DIR/regions-close-over-type-parameter-1.rs:20:5 + --> $DIR/regions-close-over-type-parameter-1.rs:21:5 | LL | box v as Box | ^^^^^ -error[E0309]: the parameter type `A` may not live long enough - --> $DIR/regions-close-over-type-parameter-1.rs:20:5 - | -LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound...: `A: 'b +` -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that it can be closed over into an object - --> $DIR/regions-close-over-type-parameter-1.rs:20:5 - | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0309, E0310. For more information about an error, try `rustc --explain E0309`. diff --git a/src/test/ui/regions/regions-escape-method.nll.stderr b/src/test/ui/regions/regions-escape-method.nll.stderr deleted file mode 100644 index 9f425125b9896..0000000000000 --- a/src/test/ui/regions/regions-escape-method.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-escape-method.rs:15:13 - | -LL | s.f(|p| p) - | -- ^ returning this value requires that `'1` must outlive `'2` - | || - | |return type of closure is &'2 i32 - | has type `&'1 i32` - -error: aborting due to previous error - diff --git a/src/test/ui/regions/regions-escape-method.rs b/src/test/ui/regions/regions-escape-method.rs index 5127d4d1ceb0f..69c01ae6906cb 100644 --- a/src/test/ui/regions/regions-escape-method.rs +++ b/src/test/ui/regions/regions-escape-method.rs @@ -12,5 +12,5 @@ impl S { fn main() { let s = S; - s.f(|p| p) //~ ERROR cannot infer + s.f(|p| p) //~ ERROR lifetime may not live long enough } diff --git a/src/test/ui/regions/regions-escape-method.stderr b/src/test/ui/regions/regions-escape-method.stderr index ffc2a259485aa..9f425125b9896 100644 --- a/src/test/ui/regions/regions-escape-method.stderr +++ b/src/test/ui/regions/regions-escape-method.stderr @@ -1,32 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error: lifetime may not live long enough --> $DIR/regions-escape-method.rs:15:13 | LL | s.f(|p| p) - | ^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:9... - --> $DIR/regions-escape-method.rs:15:9 - | -LL | s.f(|p| p) - | ^^^^^ -note: ...so that the expression is assignable - --> $DIR/regions-escape-method.rs:15:13 - | -LL | s.f(|p| p) - | ^ - = note: expected `&i32` - found `&i32` -note: but, the lifetime must be valid for the method call at 15:5... - --> $DIR/regions-escape-method.rs:15:5 - | -LL | s.f(|p| p) - | ^^^^^^^^^^ -note: ...so that a type/lifetime parameter is in scope here - --> $DIR/regions-escape-method.rs:15:5 - | -LL | s.f(|p| p) - | ^^^^^^^^^^ + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 i32 + | has type `&'1 i32` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr deleted file mode 100644 index cae6c33ac6e17..0000000000000 --- a/src/test/ui/regions/regions-escape-via-trait-or-not.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-escape-via-trait-or-not.rs:18:14 - | -LL | with(|o| o) - | -- ^ returning this value requires that `'1` must outlive `'2` - | || - | |return type of closure is &'2 isize - | has type `&'1 isize` - -error: aborting due to previous error - diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.rs b/src/test/ui/regions/regions-escape-via-trait-or-not.rs index 1e089616f5997..ac0e56de4a030 100644 --- a/src/test/ui/regions/regions-escape-via-trait-or-not.rs +++ b/src/test/ui/regions/regions-escape-via-trait-or-not.rs @@ -15,7 +15,7 @@ fn with(f: F) -> isize where F: FnOnce(&isize) -> R { } fn return_it() -> isize { - with(|o| o) //~ ERROR cannot infer + with(|o| o) //~ ERROR lifetime may not live long enough } fn main() { diff --git a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr index 90823464c56d2..cae6c33ac6e17 100644 --- a/src/test/ui/regions/regions-escape-via-trait-or-not.stderr +++ b/src/test/ui/regions/regions-escape-via-trait-or-not.stderr @@ -1,32 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements +error: lifetime may not live long enough --> $DIR/regions-escape-via-trait-or-not.rs:18:14 | LL | with(|o| o) - | ^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 18:10... - --> $DIR/regions-escape-via-trait-or-not.rs:18:10 - | -LL | with(|o| o) - | ^^^^^ -note: ...so that the expression is assignable - --> $DIR/regions-escape-via-trait-or-not.rs:18:14 - | -LL | with(|o| o) - | ^ - = note: expected `&isize` - found `&isize` -note: but, the lifetime must be valid for the expression at 18:5... - --> $DIR/regions-escape-via-trait-or-not.rs:18:5 - | -LL | with(|o| o) - | ^^^^ -note: ...so type `fn([closure@$DIR/regions-escape-via-trait-or-not.rs:18:10: 18:15]) -> isize {with::<&isize, [closure@$DIR/regions-escape-via-trait-or-not.rs:18:10: 18:15]>}` of expression is valid during the expression - --> $DIR/regions-escape-via-trait-or-not.rs:18:5 - | -LL | with(|o| o) - | ^^^^ + | -- ^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-infer-call-3.nll.stderr b/src/test/ui/regions/regions-infer-call-3.nll.stderr deleted file mode 100644 index ca51555a07749..0000000000000 --- a/src/test/ui/regions/regions-infer-call-3.nll.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: lifetime may not live long enough - --> $DIR/regions-infer-call-3.rs:8:24 - | -LL | let z = with(|y| { select(x, y) }); - | -- ^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` - | || - | |return type of closure is &'2 isize - | has type `&'1 isize` - -error: aborting due to previous error - diff --git a/src/test/ui/regions/regions-infer-call-3.rs b/src/test/ui/regions/regions-infer-call-3.rs index a76fccbdc5218..063ec84288d1f 100644 --- a/src/test/ui/regions/regions-infer-call-3.rs +++ b/src/test/ui/regions/regions-infer-call-3.rs @@ -6,7 +6,7 @@ fn with(f: F) -> T where F: FnOnce(&isize) -> T { fn manip<'a>(x: &'a isize) -> isize { let z = with(|y| { select(x, y) }); - //~^ ERROR cannot infer + //~^ ERROR lifetime may not live long enough *z } diff --git a/src/test/ui/regions/regions-infer-call-3.stderr b/src/test/ui/regions/regions-infer-call-3.stderr index 1d6dbdb2c7b57..ca51555a07749 100644 --- a/src/test/ui/regions/regions-infer-call-3.stderr +++ b/src/test/ui/regions/regions-infer-call-3.stderr @@ -1,30 +1,11 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'r in function call due to conflicting requirements +error: lifetime may not live long enough --> $DIR/regions-infer-call-3.rs:8:24 | LL | let z = with(|y| { select(x, y) }); - | ^^^^^^^^^^^^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 8:18... - --> $DIR/regions-infer-call-3.rs:8:18 - | -LL | let z = with(|y| { select(x, y) }); - | ^^^^^^^^^^^^^^^^^^^^ -note: ...so that reference does not outlive borrowed content - --> $DIR/regions-infer-call-3.rs:8:34 - | -LL | let z = with(|y| { select(x, y) }); - | ^ -note: but, the lifetime must be valid for the call at 8:13... - --> $DIR/regions-infer-call-3.rs:8:13 - | -LL | let z = with(|y| { select(x, y) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...so type `&isize` of expression is valid during the expression - --> $DIR/regions-infer-call-3.rs:8:13 - | -LL | let z = with(|y| { select(x, y) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -- ^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | || + | |return type of closure is &'2 isize + | has type `&'1 isize` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr deleted file mode 100644 index 4c275b19492c6..0000000000000 --- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: captured variable cannot escape `FnMut` closure body - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24 - | -LL | let mut f = || &mut x; - | - ^^^^^^ returns a reference to a captured variable which escapes the closure body - | | - | inferred to be a `FnMut` closure - | - = note: `FnMut` closures only have access to their captured variables while they are executing... - = note: ...therefore, they cannot allow references to captured variables to escape - -error: aborting due to previous error - diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs index afe87f47eadbe..86e759f088a54 100644 --- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs @@ -4,7 +4,7 @@ fn main() { // Unboxed closure case { let mut x = 0; - let mut f = || &mut x; //~ ERROR cannot infer + let mut f = || &mut x; //~ ERROR captured variable cannot escape `FnMut` closure body let x = f(); let y = f(); } diff --git a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr index 946465bcb5f26..4c275b19492c6 100644 --- a/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr +++ b/src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr @@ -1,30 +1,13 @@ -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements +error: captured variable cannot escape `FnMut` closure body --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24 | LL | let mut f = || &mut x; - | ^^^^^^ + | - ^^^^^^ returns a reference to a captured variable which escapes the closure body + | | + | inferred to be a `FnMut` closure | -note: first, the lifetime cannot outlive the lifetime `'_` as defined on the body at 7:21... - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:21 - | -LL | let mut f = || &mut x; - | ^^^^^^^^^ -note: ...so that closure can access `x` - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24 - | -LL | let mut f = || &mut x; - | ^^^^^^ -note: but, the lifetime must be valid for the call at 9:17... - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17 - | -LL | let y = f(); - | ^^^ -note: ...so type `&mut i32` of expression is valid during the expression - --> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17 - | -LL | let y = f(); - | ^^^ + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 1f689a5bd2541..cdcf89e4e614e 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -3,8 +3,8 @@ // revisions: legacy v0 //[legacy]compile-flags: -Z symbol-mangling-version=legacy //[v0]compile-flags: -Z symbol-mangling-version=v0 -//[legacy]normalize-stderr-32bit: "hdb62078998ce7ea8" -> "SYMBOL_HASH" -//[legacy]normalize-stderr-64bit: "h62e540f14f879d56" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-32bit: "h5ef5dfc14aeecbfc" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-64bit: "h9e54d216f70fcbc5" -> "SYMBOL_HASH" #![feature(optin_builtin_traits, rustc_attrs)] #![allow(dead_code)] From 9754b3fc1d9d24bc1e65136e5798cc5a6d226a4f Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 21 May 2020 18:44:25 +0100 Subject: [PATCH 166/695] Document `collect_bounding_regions` --- .../infer/lexical_region_resolve/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs index ef3eb24f28852..fcf1949933b11 100644 --- a/src/librustc_infer/infer/lexical_region_resolve/mod.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs @@ -862,6 +862,17 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ); } + /// Collects all regions that "bound" the variable `orig_node_idx` in the + /// given direction. + /// + /// If `dup_vec` is `Some` it's used to track duplicates between successive + /// calls of this function. + /// + /// The return tuple fields are: + /// - a list of all concrete regions bounding the given region. + /// - the set of all region variables bounding the given region. + /// - a `bool` that's true if the returned region variables overlap with + /// those returned by a previous call for another region. fn collect_bounding_regions( &self, graph: &RegionGraph<'tcx>, From 4b516279a91701eaef7100ea321a38016993c06c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Fri, 22 May 2020 19:06:28 +0200 Subject: [PATCH 167/695] Revert MSYS2 CI workaround --- src/ci/scripts/install-msys2-packages.sh | 11 ----------- src/ci/scripts/install-msys2.sh | 3 +-- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/ci/scripts/install-msys2-packages.sh b/src/ci/scripts/install-msys2-packages.sh index 8fefddd959c9c..ff7479c05d04e 100755 --- a/src/ci/scripts/install-msys2-packages.sh +++ b/src/ci/scripts/install-msys2-packages.sh @@ -6,17 +6,6 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows; then - # FIXME(mati865): temporary workaround until chocolatey updates their MSYS2 - base_url='https://ci-mirrors.rust-lang.org/rustc/msys2-repo/msys/x86_64' - curl ${base_url}/libzstd-1.4.4-2-x86_64.pkg.tar.xz -o libzstd-1.4.4-2-x86_64.pkg.tar.xz - curl ${base_url}/pacman-5.2.1-6-x86_64.pkg.tar.xz -o pacman-5.2.1-6-x86_64.pkg.tar.xz - curl ${base_url}/zstd-1.4.4-2-x86_64.pkg.tar.xz -o zstd-1.4.4-2-x86_64.pkg.tar.xz - pacman -U --noconfirm libzstd-1.4.4-2-x86_64.pkg.tar.xz pacman-5.2.1-6-x86_64.pkg.tar.xz \ - zstd-1.4.4-2-x86_64.pkg.tar.xz - rm libzstd-1.4.4-2-x86_64.pkg.tar.xz pacman-5.2.1-6-x86_64.pkg.tar.xz \ - zstd-1.4.4-2-x86_64.pkg.tar.xz - pacman -Sy - pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar \ binutils diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh index b94eb5fc6ddd5..3c3b5007f8697 100755 --- a/src/ci/scripts/install-msys2.sh +++ b/src/ci/scripts/install-msys2.sh @@ -17,9 +17,8 @@ if isWindows; then msys2.nupkg curl -sSL https://packages.chocolatey.org/chocolatey-core.extension.1.3.5.1.nupkg > \ chocolatey-core.extension.nupkg - # FIXME(mati865): remove `/NoUpdate` once chocolatey updates MSYS2 choco install -s . msys2 \ - --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath /NoUpdate" -y --no-progress + --params="/InstallDir:$(ciCheckoutPath)/msys2 /NoPath" -y --no-progress rm msys2.nupkg chocolatey-core.extension.nupkg mkdir -p "$(ciCheckoutPath)/msys2/home/${USERNAME}" ciCommandAddPath "$(ciCheckoutPath)/msys2/usr/bin" From 29d043683e6f70b22ae34596b4cb9ae07274c28b Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Fri, 22 May 2020 19:09:24 +0200 Subject: [PATCH 168/695] option_option test case #4298 --- tests/ui/option_option.rs | 25 +++++++++++++++++++++++++ tests/ui/option_option.stderr | 8 +++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index 904c50e14039a..a2617a13ecace 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -60,3 +60,28 @@ fn main() { // The lint allows this let expr = Some(Some(true)); } + +extern crate serde; +mod issue_4298 { + use serde::{Deserialize, Deserializer, Serialize}; + use std::borrow::Cow; + + #[derive(Serialize, Deserialize)] + struct Foo<'a> { + #[serde(deserialize_with = "func")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + #[serde(borrow)] + // FIXME: should not lint here + #[allow(clippy::option_option)] + foo: Option>>, + } + + #[allow(clippy::option_option)] + fn func<'a, D>(_: D) -> Result>>, D::Error> + where + D: Deserializer<'a>, + { + Ok(Some(Some(Cow::Borrowed("hi")))) + } +} diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 79db186d7ea77..0cd4c96eb4f9a 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -58,5 +58,11 @@ error: consider using `Option` instead of `Option>` or a custom enu LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases + --> $DIR/option_option.rs:77:14 + | +LL | foo: Option>>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors From 7a4c1865fb2f58c57e3f09645515dec8be3022c6 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 May 2020 00:00:33 -0400 Subject: [PATCH 169/695] Move functions to librustc_parse --- src/librustc_ast/token.rs | 56 -------------- src/librustc_ast/tokenstream.rs | 121 ------------------------------- src/librustc_parse/lib.rs | 125 +++++++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 179 deletions(-) diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index a5b9c2a95bbea..2e2bc380e844f 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -673,62 +673,6 @@ impl Token { Some(Token::new(kind, self.span.to(joint.span))) } - - // See comments in `Nonterminal::to_tokenstream` for why we care about - // *probably* equal here rather than actual equality - crate fn probably_equal_for_proc_macro(&self, other: &Token) -> bool { - if mem::discriminant(&self.kind) != mem::discriminant(&other.kind) { - return false; - } - match (&self.kind, &other.kind) { - (&Eq, &Eq) - | (&Lt, &Lt) - | (&Le, &Le) - | (&EqEq, &EqEq) - | (&Ne, &Ne) - | (&Ge, &Ge) - | (&Gt, &Gt) - | (&AndAnd, &AndAnd) - | (&OrOr, &OrOr) - | (&Not, &Not) - | (&Tilde, &Tilde) - | (&At, &At) - | (&Dot, &Dot) - | (&DotDot, &DotDot) - | (&DotDotDot, &DotDotDot) - | (&DotDotEq, &DotDotEq) - | (&Comma, &Comma) - | (&Semi, &Semi) - | (&Colon, &Colon) - | (&ModSep, &ModSep) - | (&RArrow, &RArrow) - | (&LArrow, &LArrow) - | (&FatArrow, &FatArrow) - | (&Pound, &Pound) - | (&Dollar, &Dollar) - | (&Question, &Question) - | (&Whitespace, &Whitespace) - | (&Comment, &Comment) - | (&Eof, &Eof) => true, - - (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b, - - (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b, - - (&DocComment(a), &DocComment(b)) | (&Shebang(a), &Shebang(b)) => a == b, - - (&Literal(a), &Literal(b)) => a == b, - - (&Lifetime(a), &Lifetime(b)) => a == b, - (&Ident(a, b), &Ident(c, d)) => { - b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate) - } - - (&Interpolated(_), &Interpolated(_)) => false, - - _ => panic!("forgot to add a token?"), - } - } } impl PartialEq for Token { diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index 075aaa7e5bc01..7348c41dbe778 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -68,23 +68,6 @@ impl TokenTree { } } - // See comments in `Nonterminal::to_tokenstream` for why we care about - // *probably* equal here rather than actual equality - // - // This is otherwise the same as `eq_unspanned`, only recursing with a - // different method. - pub fn probably_equal_for_proc_macro(&self, other: &TokenTree) -> bool { - match (self, other) { - (TokenTree::Token(token), TokenTree::Token(token2)) => { - token.probably_equal_for_proc_macro(token2) - } - (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tts.probably_equal_for_proc_macro(&tts2) - } - _ => false, - } - } - /// Retrieves the TokenTree's span. pub fn span(&self) -> Span { match self { @@ -307,111 +290,7 @@ impl TokenStream { t1.next().is_none() && t2.next().is_none() } - // See comments in `Nonterminal::to_tokenstream` for why we care about - // *probably* equal here rather than actual equality - // - // This is otherwise the same as `eq_unspanned`, only recursing with a - // different method. - pub fn probably_equal_for_proc_macro(&self, other: &TokenStream) -> bool { - // When checking for `probably_eq`, we ignore certain tokens that aren't - // preserved in the AST. Because they are not preserved, the pretty - // printer arbitrarily adds or removes them when printing as token - // streams, making a comparison between a token stream generated from an - // AST and a token stream which was parsed into an AST more reliable. - fn semantic_tree(tree: &TokenTree) -> bool { - if let TokenTree::Token(token) = tree { - if let - // The pretty printer tends to add trailing commas to - // everything, and in particular, after struct fields. - | token::Comma - // The pretty printer emits `NoDelim` as whitespace. - | token::OpenDelim(DelimToken::NoDelim) - | token::CloseDelim(DelimToken::NoDelim) - // The pretty printer collapses many semicolons into one. - | token::Semi - // The pretty printer collapses whitespace arbitrarily and can - // introduce whitespace from `NoDelim`. - | token::Whitespace - // The pretty printer can turn `$crate` into `::crate_name` - | token::ModSep = token.kind { - return false; - } - } - true - } - // When comparing two `TokenStream`s, we ignore the `IsJoint` information. - // - // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will - // use `Token.glue` on adjacent tokens with the proper `IsJoint`. - // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`) - // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent - // when determining if two `TokenStream`s are 'probably equal'. - // - // Therefore, we use `break_two_token_op` to convert all tokens - // to the 'unglued' form (if it exists). This ensures that two - // `TokenStream`s which differ only in how their tokens are glued - // will be considered 'probably equal', which allows us to keep spans. - // - // This is important when the original `TokenStream` contained - // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces - // will be omitted when we pretty-print, which can cause the original - // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`, - // leading to some tokens being 'glued' together in one stream but not - // the other. See #68489 for more details. - fn break_tokens(tree: TokenTree) -> impl Iterator { - // In almost all cases, we should have either zero or one levels - // of 'unglueing'. However, in some unusual cases, we may need - // to iterate breaking tokens mutliple times. For example: - // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]' - let mut token_trees: SmallVec<[_; 2]>; - if let TokenTree::Token(token) = &tree { - let mut out = SmallVec::<[_; 2]>::new(); - out.push(token.clone()); - // Iterate to fixpoint: - // * We start off with 'out' containing our initial token, and `temp` empty - // * If we are able to break any tokens in `out`, then `out` will have - // at least one more element than 'temp', so we will try to break tokens - // again. - // * If we cannot break any tokens in 'out', we are done - loop { - let mut temp = SmallVec::<[_; 2]>::new(); - let mut changed = false; - - for token in out.into_iter() { - if let Some((first, second)) = token.kind.break_two_token_op() { - temp.push(Token::new(first, DUMMY_SP)); - temp.push(Token::new(second, DUMMY_SP)); - changed = true; - } else { - temp.push(token); - } - } - out = temp; - if !changed { - break; - } - } - token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect(); - if token_trees.len() != 1 { - debug!("break_tokens: broke {:?} to {:?}", tree, token_trees); - } - } else { - token_trees = SmallVec::new(); - token_trees.push(tree); - } - token_trees.into_iter() - } - - let mut t1 = self.trees().filter(semantic_tree).flat_map(break_tokens); - let mut t2 = other.trees().filter(semantic_tree).flat_map(break_tokens); - for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !t1.probably_equal_for_proc_macro(&t2) { - return false; - } - } - t1.next().is_none() && t2.next().is_none() - } pub fn map_enumerated TokenTree>(self, mut f: F) -> TokenStream { TokenStream(Lrc::new( diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 8e2a9513d6b82..9d548fa0e81ad 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -7,16 +7,18 @@ #![feature(or_patterns)] use rustc_ast::ast; -use rustc_ast::token::{self, Nonterminal}; +use rustc_ast::token::{self, Nonterminal, Token, TokenKind, DelimToken}; use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; +use rustc_span::symbol::kw; use std::path::Path; use std::str; +use std::mem; use log::info; @@ -300,7 +302,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokens.probably_equal_for_proc_macro(&tokens_for_real) { + if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real) { return tokens; } info!( @@ -373,3 +375,122 @@ fn prepend_attrs( builder.push(tokens.clone()); Some(builder.build()) } + +// See comments in `Nonterminal::to_tokenstream` for why we care about +// *probably* equal here rather than actual equality +// +// This is otherwise the same as `eq_unspanned`, only recursing with a +// different method. +pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &TokenStream) -> bool { + // When checking for `probably_eq`, we ignore certain tokens that aren't + // preserved in the AST. Because they are not preserved, the pretty + // printer arbitrarily adds or removes them when printing as token + // streams, making a comparison between a token stream generated from an + // AST and a token stream which was parsed into an AST more reliable. + fn semantic_tree(tree: &TokenTree) -> bool { + if let TokenTree::Token(token) = tree { + if let + // The pretty printer tends to add trailing commas to + // everything, and in particular, after struct fields. + | token::Comma + // The pretty printer emits `NoDelim` as whitespace. + | token::OpenDelim(DelimToken::NoDelim) + | token::CloseDelim(DelimToken::NoDelim) + // The pretty printer collapses many semicolons into one. + | token::Semi + // The pretty printer collapses whitespace arbitrarily and can + // introduce whitespace from `NoDelim`. + | token::Whitespace + // The pretty printer can turn `$crate` into `::crate_name` + | token::ModSep = token.kind { + return false; + } + } + true + } + + let mut t1 = first.trees().filter(semantic_tree); + let mut t2 = other.trees().filter(semantic_tree); + for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { + if !tokentree_probably_equal_for_proc_macro(&t1, &t2) { + return false; + } + } + t1.next().is_none() && t2.next().is_none() +} + +// See comments in `Nonterminal::to_tokenstream` for why we care about +// *probably* equal here rather than actual equality +crate fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { + use TokenKind::*; + + if mem::discriminant(&first.kind) != mem::discriminant(&other.kind) { + return false; + } + match (&first.kind, &other.kind) { + (&Eq, &Eq) + | (&Lt, &Lt) + | (&Le, &Le) + | (&EqEq, &EqEq) + | (&Ne, &Ne) + | (&Ge, &Ge) + | (&Gt, &Gt) + | (&AndAnd, &AndAnd) + | (&OrOr, &OrOr) + | (&Not, &Not) + | (&Tilde, &Tilde) + | (&At, &At) + | (&Dot, &Dot) + | (&DotDot, &DotDot) + | (&DotDotDot, &DotDotDot) + | (&DotDotEq, &DotDotEq) + | (&Comma, &Comma) + | (&Semi, &Semi) + | (&Colon, &Colon) + | (&ModSep, &ModSep) + | (&RArrow, &RArrow) + | (&LArrow, &LArrow) + | (&FatArrow, &FatArrow) + | (&Pound, &Pound) + | (&Dollar, &Dollar) + | (&Question, &Question) + | (&Whitespace, &Whitespace) + | (&Comment, &Comment) + | (&Eof, &Eof) => true, + + (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b, + + (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b, + + (&DocComment(a), &DocComment(b)) | (&Shebang(a), &Shebang(b)) => a == b, + + (&Literal(a), &Literal(b)) => a == b, + + (&Lifetime(a), &Lifetime(b)) => a == b, + (&Ident(a, b), &Ident(c, d)) => { + b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate) + } + + (&Interpolated(_), &Interpolated(_)) => false, + + _ => panic!("forgot to add a token?"), + } +} + + +// See comments in `Nonterminal::to_tokenstream` for why we care about +// *probably* equal here rather than actual equality +// +// This is otherwise the same as `eq_unspanned`, only recursing with a +// different method. +pub fn tokentree_probably_equal_for_proc_macro(first: &TokenTree, other: &TokenTree) -> bool { + match (first, other) { + (TokenTree::Token(token), TokenTree::Token(token2)) => { + token_probably_equal_for_proc_macro(token, token2) + } + (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { + delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2) + } + _ => false, + } +} From 2af0218bf1ffca0750a352554f20a07b760a30a8 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 May 2020 00:13:24 -0400 Subject: [PATCH 170/695] Recursively expand nonterminals --- src/librustc_ast/tokenstream.rs | 2 - src/librustc_parse/lib.rs | 109 ++++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index 7348c41dbe778..ff3469930c6d3 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -290,8 +290,6 @@ impl TokenStream { t1.next().is_none() && t2.next().is_none() } - - pub fn map_enumerated TokenTree>(self, mut f: F) -> TokenStream { TokenStream(Lrc::new( self.0 diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 9d548fa0e81ad..352278d252616 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -7,20 +7,20 @@ #![feature(or_patterns)] use rustc_ast::ast; -use rustc_ast::token::{self, Nonterminal, Token, TokenKind, DelimToken}; -use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; +use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; +use rustc_ast::tokenstream::{self, IsJoint, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::{FileName, SourceFile, Span}; use rustc_span::symbol::kw; +use rustc_span::{FileName, SourceFile, Span}; +use std::mem; use std::path::Path; use std::str; -use std::mem; -use log::info; +use log::{debug, info}; pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); @@ -302,7 +302,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real) { + if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real, sess) { return tokens; } info!( @@ -381,7 +381,11 @@ fn prepend_attrs( // // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. -pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &TokenStream) -> bool { +pub fn tokenstream_probably_equal_for_proc_macro( + first: &TokenStream, + other: &TokenStream, + sess: &ParseSess, +) -> bool { // When checking for `probably_eq`, we ignore certain tokens that aren't // preserved in the AST. Because they are not preserved, the pretty // printer arbitrarily adds or removes them when printing as token @@ -409,10 +413,83 @@ pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &To true } - let mut t1 = first.trees().filter(semantic_tree); - let mut t2 = other.trees().filter(semantic_tree); + // When comparing two `TokenStream`s, we ignore the `IsJoint` information. + // + // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will + // use `Token.glue` on adjacent tokens with the proper `IsJoint`. + // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`) + // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent + // when determining if two `TokenStream`s are 'probably equal'. + // + // Therefore, we use `break_two_token_op` to convert all tokens + // to the 'unglued' form (if it exists). This ensures that two + // `TokenStream`s which differ only in how their tokens are glued + // will be considered 'probably equal', which allows us to keep spans. + // + // This is important when the original `TokenStream` contained + // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces + // will be omitted when we pretty-print, which can cause the original + // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`, + // leading to some tokens being 'glued' together in one stream but not + // the other. See #68489 for more details. + fn break_tokens(tree: TokenTree) -> impl Iterator { + // In almost all cases, we should have either zero or one levels + // of 'unglueing'. However, in some unusual cases, we may need + // to iterate breaking tokens mutliple times. For example: + // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]' + let mut token_trees: SmallVec<[_; 2]>; + if let TokenTree::Token(token) = &tree { + let mut out = SmallVec::<[_; 2]>::new(); + out.push(token.clone()); + // Iterate to fixpoint: + // * We start off with 'out' containing our initial token, and `temp` empty + // * If we are able to break any tokens in `out`, then `out` will have + // at least one more element than 'temp', so we will try to break tokens + // again. + // * If we cannot break any tokens in 'out', we are done + loop { + let mut temp = SmallVec::<[_; 2]>::new(); + let mut changed = false; + + for token in out.into_iter() { + if let Some((first, second)) = token.kind.break_two_token_op() { + temp.push(Token::new(first, DUMMY_SP)); + temp.push(Token::new(second, DUMMY_SP)); + changed = true; + } else { + temp.push(token); + } + } + out = temp; + if !changed { + break; + } + } + token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect(); + if token_trees.len() != 1 { + debug!("break_tokens: broke {:?} to {:?}", tree, token_trees); + } + } else { + token_trees = SmallVec::new(); + token_trees.push(tree); + } + token_trees.into_iter() + } + + let expand_nt = |tree: TokenTree| { + if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree { + nt_to_tokenstream(nt, sess, *span).into_trees() + } else { + TokenStream::new(vec![(tree, IsJoint::NonJoint)]).into_trees() + } + }; + + // Break tokens after we expand any nonterminals, so that we break tokens + // that are produced as a result of nonterminal expansion. + let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2) { + if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) { return false; } } @@ -471,25 +548,29 @@ crate fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bo b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate) } - (&Interpolated(_), &Interpolated(_)) => false, + // Expanded by `tokenstream_probably_equal_for_proc_macro` + (&Interpolated(_), &Interpolated(_)) => unreachable!(), _ => panic!("forgot to add a token?"), } } - // See comments in `Nonterminal::to_tokenstream` for why we care about // *probably* equal here rather than actual equality // // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. -pub fn tokentree_probably_equal_for_proc_macro(first: &TokenTree, other: &TokenTree) -> bool { +pub fn tokentree_probably_equal_for_proc_macro( + first: &TokenTree, + other: &TokenTree, + sess: &ParseSess, +) -> bool { match (first, other) { (TokenTree::Token(token), TokenTree::Token(token2)) => { token_probably_equal_for_proc_macro(token, token2) } (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2) + delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2, sess) } _ => false, } From 30c00fd26a24f349df64a7c0f5c3490e9f624322 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 May 2020 13:16:29 -0400 Subject: [PATCH 171/695] Add test for macro_rules! invoking a proc-macro with capture groups --- src/test/ui/proc-macro/macro-rules-capture.rs | 18 ++++++++++++++++++ .../ui/proc-macro/macro-rules-capture.stderr | 12 ++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/test/ui/proc-macro/macro-rules-capture.rs create mode 100644 src/test/ui/proc-macro/macro-rules-capture.stderr diff --git a/src/test/ui/proc-macro/macro-rules-capture.rs b/src/test/ui/proc-macro/macro-rules-capture.rs new file mode 100644 index 0000000000000..37436567d70f0 --- /dev/null +++ b/src/test/ui/proc-macro/macro-rules-capture.rs @@ -0,0 +1,18 @@ +// aux-build: test-macros.rs + +extern crate test_macros; +use test_macros::recollect_attr; + +macro_rules! reemit { + ($name:ident => $($token:expr)*) => { + + #[recollect_attr] + pub fn $name() { + $($token)*; + } + } +} + +reemit! { foo => 45u32.into() } //~ ERROR type annotations + +fn main() {} diff --git a/src/test/ui/proc-macro/macro-rules-capture.stderr b/src/test/ui/proc-macro/macro-rules-capture.stderr new file mode 100644 index 0000000000000..6d512846ff785 --- /dev/null +++ b/src/test/ui/proc-macro/macro-rules-capture.stderr @@ -0,0 +1,12 @@ +error[E0282]: type annotations needed + --> $DIR/macro-rules-capture.rs:16:24 + | +LL | reemit! { foo => 45u32.into() } + | ------^^^^-- + | | | + | | cannot infer type for type parameter `T` declared on the trait `Into` + | this method call resolves to `T` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. From 5685e4dd90ad2f4978c63b9097f0b568e4ce6e5c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 22 May 2020 15:11:49 -0400 Subject: [PATCH 172/695] Fix rebase fallout --- Cargo.lock | 1 + src/librustc_ast/tokenstream.rs | 2 -- src/librustc_parse/Cargo.toml | 1 + src/librustc_parse/lib.rs | 4 +++- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d81fd6e8d3afd..2394565dfb0dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4173,6 +4173,7 @@ dependencies = [ "rustc_lexer", "rustc_session", "rustc_span", + "smallvec 1.4.0", "unicode-normalization", ] diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index ff3469930c6d3..9d0199078fa6a 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -21,8 +21,6 @@ use rustc_macros::HashStable_Generic; use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; -use log::debug; - use std::{iter, mem}; /// When the main rust parser encounters a syntax-extension invocation, it diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml index 7164c67880863..0d31a8c7bc1fb 100644 --- a/src/librustc_parse/Cargo.toml +++ b/src/librustc_parse/Cargo.toml @@ -12,6 +12,7 @@ doctest = false [dependencies] bitflags = "1.0" log = "0.4" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_feature = { path = "../librustc_feature" } diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 352278d252616..0c817a712819f 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -14,7 +14,9 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; -use rustc_span::{FileName, SourceFile, Span}; +use rustc_span::{FileName, SourceFile, Span, DUMMY_SP}; + +use smallvec::SmallVec; use std::mem; use std::path::Path; From 9f82785c81c68d117617b6b45bce437649f94833 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 May 2020 21:43:06 -0700 Subject: [PATCH 173/695] Replace `rustc_data_structures::sync::Once` with `OnceCell` --- Cargo.lock | 1 + src/librustc_data_structures/Cargo.toml | 1 + src/librustc_data_structures/sync.rs | 133 +----------------------- src/tools/tidy/src/deps.rs | 1 + 4 files changed, 7 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d81fd6e8d3afd..ebcc11d2b26d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3791,6 +3791,7 @@ dependencies = [ "libc", "log", "measureme", + "once_cell", "parking_lot 0.10.2", "rustc-hash", "rustc-rayon", diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 81ad032967bfd..67721220526ca 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -15,6 +15,7 @@ indexmap = "1" log = "0.4" jobserver_crate = { version = "0.1.13", package = "jobserver" } lazy_static = "1" +once_cell = { version = "1", features = ["parking_lot"] } rustc_serialize = { path = "../libserialize", package = "serialize" } graphviz = { path = "../libgraphviz" } cfg-if = "0.1.2" diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 9051b1751b119..39afb3d82ff5a 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -20,7 +20,6 @@ use crate::owning_ref::{Erased, OwningRef}; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; -use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; pub use std::sync::atomic::Ordering; @@ -230,6 +229,8 @@ cfg_if! { pub use std::cell::RefMut as LockGuard; pub use std::cell::RefMut as MappedLockGuard; + pub use once_cell::unsync::OnceCell; + use std::cell::RefCell as InnerRwLock; use std::cell::RefCell as InnerLock; @@ -313,6 +314,8 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; pub use parking_lot::MappedMutexGuard as MappedLockGuard; + pub use once_cell::sync::OnceCell; + pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; pub use crossbeam_utils::atomic::AtomicCell; @@ -432,134 +435,6 @@ impl HashMapExt for HashMap } } -/// A type whose inner value can be written once and then will stay read-only -// This contains a PhantomData since this type conceptually owns a T outside the Mutex once -// initialized. This ensures that Once is Sync only if T is. If we did not have PhantomData -// we could send a &Once> to multiple threads and call `get` on it to get access -// to &Cell on those threads. -pub struct Once(Lock>, PhantomData); - -impl Once { - /// Creates an Once value which is uninitialized - #[inline(always)] - pub fn new() -> Self { - Once(Lock::new(None), PhantomData) - } - - /// Consumes the value and returns Some(T) if it was initialized - #[inline(always)] - pub fn into_inner(self) -> Option { - self.0.into_inner() - } - - /// Tries to initialize the inner value to `value`. - /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it - /// otherwise if the inner value was already set it returns `value` back to the caller - #[inline] - pub fn try_set(&self, value: T) -> Option { - let mut lock = self.0.lock(); - if lock.is_some() { - return Some(value); - } - *lock = Some(value); - None - } - - /// Tries to initialize the inner value to `value`. - /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it - /// otherwise if the inner value was already set it asserts that `value` is equal to the inner - /// value and then returns `value` back to the caller - #[inline] - pub fn try_set_same(&self, value: T) -> Option - where - T: Eq, - { - let mut lock = self.0.lock(); - if let Some(ref inner) = *lock { - assert!(*inner == value); - return Some(value); - } - *lock = Some(value); - None - } - - /// Tries to initialize the inner value to `value` and panics if it was already initialized - #[inline] - pub fn set(&self, value: T) { - assert!(self.try_set(value).is_none()); - } - - /// Initializes the inner value if it wasn't already done by calling the provided closure. It - /// ensures that no-one else can access the value in the mean time by holding a lock for the - /// duration of the closure. - /// A reference to the inner value is returned. - #[inline] - pub fn init_locking T>(&self, f: F) -> &T { - { - let mut lock = self.0.lock(); - if lock.is_none() { - *lock = Some(f()); - } - } - - self.borrow() - } - - /// Tries to initialize the inner value by calling the closure without ensuring that no-one - /// else can access it. This mean when this is called from multiple threads, multiple - /// closures may concurrently be computing a value which the inner value should take. - /// Only one of these closures are used to actually initialize the value. - /// If some other closure already set the value, - /// we return the value our closure computed wrapped in a `Option`. - /// If our closure set the value, `None` is returned. - /// If the value is already initialized, the closure is not called and `None` is returned. - #[inline] - pub fn init_nonlocking T>(&self, f: F) -> Option { - if self.0.lock().is_some() { None } else { self.try_set(f()) } - } - - /// Tries to initialize the inner value by calling the closure without ensuring that no-one - /// else can access it. This mean when this is called from multiple threads, multiple - /// closures may concurrently be computing a value which the inner value should take. - /// Only one of these closures are used to actually initialize the value. - /// If some other closure already set the value, we assert that it our closure computed - /// a value equal to the value already set and then - /// we return the value our closure computed wrapped in a `Option`. - /// If our closure set the value, `None` is returned. - /// If the value is already initialized, the closure is not called and `None` is returned. - #[inline] - pub fn init_nonlocking_same T>(&self, f: F) -> Option - where - T: Eq, - { - if self.0.lock().is_some() { None } else { self.try_set_same(f()) } - } - - /// Tries to get a reference to the inner value, returns `None` if it is not yet initialized - #[inline(always)] - pub fn try_get(&self) -> Option<&T> { - let lock = &*self.0.lock(); - if let Some(ref inner) = *lock { - // This is safe since we won't mutate the inner value - unsafe { Some(&*(inner as *const T)) } - } else { - None - } - } - - /// Gets reference to the inner value, panics if it is not yet initialized - #[inline(always)] - pub fn get(&self) -> &T { - self.try_get().expect("value was not set") - } - - /// Gets reference to the inner value, panics if it is not yet initialized - #[inline(always)] - pub fn borrow(&self) -> &T { - self.get() - } -} - #[derive(Debug)] pub struct Lock(InnerLock); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index d3c7b7a068bc3..61389028cc78c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -128,6 +128,7 @@ const WHITELIST: &[&str] = &[ "miniz_oxide", "nodrop", "num_cpus", + "once_cell", "opaque-debug", "parking_lot", "parking_lot_core", From c282c1c654901bd523774dd7ce2e8d4272d24911 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 May 2020 21:44:28 -0700 Subject: [PATCH 174/695] Use `OnceCell` instead of `Once` --- Cargo.lock | 3 + src/librustc_ast_lowering/lib.rs | 2 +- src/librustc_codegen_llvm/context.rs | 2 +- src/librustc_codegen_ssa/back/link.rs | 9 +-- src/librustc_codegen_ssa/back/linker.rs | 3 +- .../back/symbol_export.rs | 4 +- src/librustc_codegen_ssa/back/write.rs | 6 +- src/librustc_codegen_ssa/base.rs | 2 +- src/librustc_driver/lib.rs | 2 +- src/librustc_driver/pretty.rs | 4 +- src/librustc_interface/passes.rs | 21 ++++--- src/librustc_interface/queries.rs | 6 +- src/librustc_interface/util.rs | 2 +- src/librustc_metadata/creader.rs | 4 +- src/librustc_metadata/dependency_format.rs | 3 +- src/librustc_metadata/locator.rs | 2 +- src/librustc_metadata/rmeta/decoder.rs | 8 +-- src/librustc_metadata/rmeta/encoder.rs | 4 +- src/librustc_middle/middle/limits.rs | 8 +-- src/librustc_middle/ty/context.rs | 2 +- src/librustc_middle/ty/layout.rs | 2 +- src/librustc_middle/ty/query/on_disk_cache.rs | 14 ++--- src/librustc_mir/const_eval/eval_queries.rs | 4 +- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 5 +- src/librustc_passes/entry.rs | 2 +- src/librustc_passes/reachable.rs | 2 +- src/librustc_passes/weak_lang_items.rs | 2 +- src/librustc_save_analysis/lib.rs | 5 +- src/librustc_session/parse.rs | 6 +- src/librustc_session/session.rs | 55 +++++++++++++------ .../traits/error_reporting/suggestions.rs | 2 +- .../traits/project.rs | 6 +- .../traits/query/normalize.rs | 2 +- src/librustc_trait_selection/traits/select.rs | 3 +- src/librustc_traits/dropck_outlives.rs | 2 +- src/librustc_ty/needs_drop.rs | 3 +- src/librustc_typeck/check/autoderef.rs | 4 +- .../clippy/clippy_lints/src/missing_inline.rs | 2 +- 39 files changed, 118 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebcc11d2b26d6..2fdbfa26787e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2327,6 +2327,9 @@ name = "once_cell" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6a04cb71e910d0034815600180f62a95bf6e67942d7ab52a166a68c7d7e9cd0" +dependencies = [ + "parking_lot 0.9.0", +] [[package]] name = "opaque-debug" diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 2cf81af04166c..0eabb726b88c9 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -269,7 +269,7 @@ pub fn lower_crate<'a, 'hir>( let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering"); LoweringContext { - crate_root: sess.parse_sess.injected_crate_name.try_get().copied(), + crate_root: sess.parse_sess.injected_crate_name.get().copied(), sess, resolver, nt_to_tokenstream, diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 3192d4fc15701..4c810a37d4180 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -174,7 +174,7 @@ pub unsafe fn create_module( llvm::LLVMRustSetModulePICLevel(llmod); // PIE is potentially more effective than PIC, but can only be used in executables. // If all our outputs are executables, then we can relax PIC to PIE. - if sess.crate_types.get().iter().all(|ty| *ty == CrateType::Executable) { + if sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) { llvm::LLVMRustSetModulePIELevel(llmod); } } diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 5de60b5b9c826..9a7c4907754b0 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -53,7 +53,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( ) { let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); - for &crate_type in sess.crate_types.borrow().iter() { + for &crate_type in sess.crate_types().iter() { // Ignore executable crates if we have -Z no-codegen, as they will error. if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) && !output_metadata @@ -875,11 +875,8 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { // If we're only producing artifacts that are archives, no need to preserve // the objects as they're losslessly contained inside the archives. - let output_linked = sess - .crate_types - .borrow() - .iter() - .any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib); + let output_linked = + sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib); if !output_linked { return false; } diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index ee5bcf4b9f58b..49de8c5e28ab5 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -44,8 +44,7 @@ impl LinkerInfo { LinkerInfo { exports: tcx .sess - .crate_types - .borrow() + .crate_types() .iter() .map(|&c| (c, exported_symbols(tcx, c))) .collect(), diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index c0272e1cd2d6b..970d13b30c04e 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{SymbolName, TyCtxt}; use rustc_session::config::{CrateType, Sanitizer}; pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { - crates_export_threshold(&tcx.sess.crate_types.borrow()) + crates_export_threshold(&tcx.sess.crate_types()) } fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel { @@ -212,7 +212,7 @@ fn exported_symbols_provider_local( })); } - if tcx.sess.crate_types.borrow().contains(&CrateType::Dylib) { + if tcx.sess.crate_types().contains(&CrateType::Dylib) { let symbol_name = metadata_symbol_name(tcx); let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index f9ee7d8c5de71..9e03c283cfb5c 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -382,7 +382,7 @@ pub struct CompiledModules { fn need_bitcode_in_object(sess: &Session) -> bool { let requested_for_rlib = sess.opts.cg.embed_bitcode - && sess.crate_types.borrow().contains(&CrateType::Rlib) + && sess.crate_types().contains(&CrateType::Rlib) && sess.opts.output_types.contains_key(&OutputType::Exe); let forced_by_target = sess.target.target.options.forces_embed_bitcode; requested_for_rlib || forced_by_target @@ -991,7 +991,7 @@ fn start_executing_work( }; let cgcx = CodegenContext:: { backend: backend.clone(), - crate_types: sess.crate_types.borrow().clone(), + crate_types: sess.crate_types().to_vec(), each_linked_rlib_for_lto, lto: sess.lto(), no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort, @@ -1812,7 +1812,7 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { ); tcx.sess.target.target.options.is_like_msvc && - tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateType::Rlib) && + tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) && // ThinLTO can't handle this workaround in all cases, so we don't // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing // dynamic linking when linker plugin LTO is enabled. diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index ed5448ca8bac4..5b14258bd25be 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -948,7 +948,7 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR match compute_per_cgu_lto_type( &tcx.sess.lto(), &tcx.sess.opts, - &tcx.sess.crate_types.borrow(), + &tcx.sess.crate_types(), ModuleKind::Regular, ) { ComputedLtoType::No => CguReuse::PostLto, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6847b175e60eb..68ce93d3db90f 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -586,7 +586,7 @@ impl RustcDefaultCalls { if let Input::File(file) = compiler.input() { // FIXME: #![crate_type] and #![crate_name] support not implemented yet let attrs = vec![]; - sess.crate_types.set(collect_crate_types(sess, &attrs)); + sess.init_crate_types(collect_crate_types(sess, &attrs)); let outputs = compiler.build_output_filenames(&sess, &attrs); let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| { sess.fatal(&format!("failed to read rlink file: {}", err)); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index a443b8f464f1c..0a21eb8de059c 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -396,7 +396,7 @@ pub fn print_after_parsing( annotation.pp_ann(), false, parse.edition, - parse.injected_crate_name.try_get().is_some(), + parse.injected_crate_name.get().is_some(), ) }) } else { @@ -438,7 +438,7 @@ pub fn print_after_hir_lowering<'tcx>( annotation.pp_ann(), true, parse.edition, - parse.injected_crate_name.try_get().is_some(), + parse.injected_crate_name.get().is_some(), ) }) } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 801c8e9329b24..214701db724ec 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -7,7 +7,7 @@ use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self, ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_data_structures::sync::{par_iter, Lrc, Once, ParallelIterator, WorkerLocal}; +use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_errors::{ErrorReported, PResult}; use rustc_expand::base::ExtCtxt; @@ -169,10 +169,10 @@ pub fn register_plugins<'a>( sess.init_features(features); let crate_types = util::collect_crate_types(sess, &krate.attrs); - sess.crate_types.set(crate_types); + sess.init_crate_types(crate_types); let disambiguator = util::compute_crate_disambiguator(sess); - sess.crate_disambiguator.set(disambiguator); + sess.crate_disambiguator.set(disambiguator).expect("not yet initialized"); rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); if sess.opts.incremental.is_some() { @@ -244,7 +244,7 @@ fn configure_and_expand_inner<'a>( alt_std_name, ); if let Some(name) = name { - sess.parse_sess.injected_crate_name.set(name); + sess.parse_sess.injected_crate_name.set(name).expect("not yet initialized"); } krate }); @@ -288,7 +288,7 @@ fn configure_and_expand_inner<'a>( let features = sess.features_untracked(); let cfg = rustc_expand::expand::ExpansionConfig { features: Some(&features), - recursion_limit: *sess.recursion_limit.get(), + recursion_limit: sess.recursion_limit(), trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) @@ -358,7 +358,7 @@ fn configure_and_expand_inner<'a>( rustc_ast_passes::ast_validation::check_crate(sess, &krate, &mut resolver.lint_buffer()) }); - let crate_types = sess.crate_types.borrow(); + let crate_types = sess.crate_types(); let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); // For backwards compatibility, we don't try to run proc macro injection @@ -488,7 +488,7 @@ fn generated_output_paths( // If the filename has been overridden using `-o`, it will not be modified // by appending `.rlib`, `.exe`, etc., so we can skip this transformation. OutputType::Exe if !exact_name => { - for crate_type in sess.crate_types.borrow().iter() { + for crate_type in sess.crate_types().iter() { let p = filename_for_input(sess, *crate_type, crate_name, outputs); out_filenames.push(p); } @@ -721,7 +721,7 @@ pub fn create_global_ctxt<'tcx>( mut resolver_outputs: ResolverOutputs, outputs: OutputFilenames, crate_name: &str, - global_ctxt: &'tcx Once>, + global_ctxt: &'tcx OnceCell>, arena: &'tcx WorkerLocal>, ) -> QueryContext<'tcx> { let sess = &compiler.session(); @@ -743,7 +743,7 @@ pub fn create_global_ctxt<'tcx>( } let gcx = sess.time("setup_global_ctxt", || { - global_ctxt.init_locking(|| { + global_ctxt.get_or_init(|| { TyCtxt::create_global_ctxt( sess, lint_store, @@ -905,8 +905,7 @@ fn encode_and_write_metadata( let metadata_kind = tcx .sess - .crate_types - .borrow() + .crate_types() .iter() .map(|ty| match *ty { CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None, diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 94cd4bcd4c626..283be165c192c 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -3,7 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc_ast::{self, ast}; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_data_structures::sync::{Lrc, Once, WorkerLocal}; +use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::ErrorReported; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::Crate; @@ -65,7 +65,7 @@ impl Default for Query { pub struct Queries<'tcx> { compiler: &'tcx Compiler, - gcx: Once>, + gcx: OnceCell>, arena: WorkerLocal>, hir_arena: WorkerLocal>, @@ -86,7 +86,7 @@ impl<'tcx> Queries<'tcx> { pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> { Queries { compiler, - gcx: Once::new(), + gcx: OnceCell::new(), arena: WorkerLocal::new(|_| Arena::default()), hir_arena: WorkerLocal::new(|_| rustc_ast_lowering::Arena::default()), dep_graph_future: Default::default(), diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 5a76802014e0d..a15da94a21561 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -406,7 +406,7 @@ pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguat // Also incorporate crate type, so that we don't get symbol conflicts when // linking against a library of the same name, if this is an executable. - let is_exe = session.crate_types.borrow().contains(&CrateType::Executable); + let is_exe = session.crate_types().contains(&CrateType::Executable); hasher.write(if is_exe { b"exe" } else { b"lib" }); CrateDisambiguator::from(hasher.finish::()) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index a9e7a9f35dc36..b0220ddd3c38e 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -615,7 +615,7 @@ impl<'a> CrateLoader<'a> { fn inject_panic_runtime(&mut self, krate: &ast::Crate) { // If we're only compiling an rlib, then there's no need to select a // panic runtime, so we just skip this section entirely. - let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| *ct != CrateType::Rlib); + let any_non_rlib = self.sess.crate_types().iter().any(|ct| *ct != CrateType::Rlib); if !any_non_rlib { info!("panic runtime injection skipped, only generating rlib"); return; @@ -734,7 +734,7 @@ impl<'a> CrateLoader<'a> { // At this point we've determined that we need an allocator. Let's see // if our compilation session actually needs an allocator based on what // we're emitting. - let all_rlib = self.sess.crate_types.borrow().iter().all(|ct| match *ct { + let all_rlib = self.sess.crate_types().iter().all(|ct| match *ct { CrateType::Rlib => true, _ => false, }); diff --git a/src/librustc_metadata/dependency_format.rs b/src/librustc_metadata/dependency_format.rs index 0876cd1e63835..aa5fafcc614b6 100644 --- a/src/librustc_metadata/dependency_format.rs +++ b/src/librustc_metadata/dependency_format.rs @@ -64,8 +64,7 @@ use rustc_target::spec::PanicStrategy; crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies { tcx.sess - .crate_types - .borrow() + .crate_types() .iter() .map(|&ty| { let linkage = calculate_type(tcx, ty); diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index f78f3c5d8d40f..5a4862d452183 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -670,7 +670,7 @@ impl<'a> CrateLocator<'a> { // The all loop is because `--crate-type=rlib --crate-type=rlib` is // legal and produces both inside this type. - let is_rlib = self.sess.crate_types.borrow().iter().all(|c| *c == CrateType::Rlib); + let is_rlib = self.sess.crate_types().iter().all(|c| *c == CrateType::Rlib); let needs_object_code = self.sess.opts.output_types.should_codegen(); // If we're producing an rlib, then we don't need object code. // Or, if we're not producing object code, then we don't need it either diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 220d74960755f..2b292b35c159d 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -10,7 +10,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, Once}; +use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, OnceCell}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive}; use rustc_hir as hir; @@ -79,7 +79,7 @@ crate struct CrateMetadata { /// Proc macro descriptions for this crate, if it's a proc macro crate. raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. - source_map_import_info: Once>, + source_map_import_info: OnceCell>, /// Used for decoding interpret::AllocIds in a cached & thread-safe manner. alloc_decoding_state: AllocDecodingState, /// The `DepNodeIndex` of the `DepNode` representing this upstream crate. @@ -1486,7 +1486,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } }; - self.cdata.source_map_import_info.init_locking(|| { + self.cdata.source_map_import_info.get_or_init(|| { let external_source_map = self.root.source_map.decode(self); external_source_map @@ -1600,7 +1600,7 @@ impl CrateMetadata { def_path_table, trait_impls, raw_proc_macros, - source_map_import_info: Once::new(), + source_map_import_info: OnceCell::new(), alloc_decoding_state, dep_node_index: AtomicCell::new(DepNodeIndex::INVALID), cnum, diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index ebe91d3cee2aa..91fbfcc0133eb 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -416,7 +416,7 @@ impl<'tcx> EncodeContext<'tcx> { } fn encode_crate_root(&mut self) -> Lazy> { - let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro); + let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro); let mut i = self.position(); @@ -1364,7 +1364,7 @@ impl EncodeContext<'tcx> { } fn encode_proc_macros(&mut self) -> Option> { - let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro); + let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro); if is_proc_macro { let tcx = self.tcx; Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index))) diff --git a/src/librustc_middle/middle/limits.rs b/src/librustc_middle/middle/limits.rs index c43c22cd61ba6..19c056925cf92 100644 --- a/src/librustc_middle/middle/limits.rs +++ b/src/librustc_middle/middle/limits.rs @@ -7,7 +7,7 @@ use crate::bug; use rustc_ast::ast; -use rustc_data_structures::sync::Once; +use rustc_data_structures::sync::OnceCell; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; @@ -22,7 +22,7 @@ pub fn update_limits(sess: &Session, krate: &ast::Crate) { fn update_limit( sess: &Session, krate: &ast::Crate, - limit: &Once, + limit: &OnceCell, name: Symbol, default: usize, ) { @@ -34,7 +34,7 @@ fn update_limit( if let Some(s) = attr.value_str() { match s.as_str().parse() { Ok(n) => { - limit.set(n); + limit.set(n).unwrap(); return; } Err(e) => { @@ -62,5 +62,5 @@ fn update_limit( } } } - limit.set(default); + limit.set(default).unwrap(); } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 5d48b3445e8a1..68c31c68075e0 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1380,7 +1380,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn local_crate_exports_generics(self) -> bool { debug_assert!(self.sess.opts.share_generics()); - self.sess.crate_types.borrow().iter().any(|crate_type| { + self.sess.crate_types().iter().any(|crate_type| { match crate_type { CrateType::Executable | CrateType::Staticlib diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 2d49d85c4df54..5566e187c0c5c 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -187,7 +187,7 @@ fn layout_raw<'tcx>( query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Result<&'tcx Layout, LayoutError<'tcx>> { ty::tls::with_related_context(tcx, move |icx| { - let rec_limit = *tcx.sess.recursion_limit.get(); + let rec_limit = tcx.sess.recursion_limit.get().copied().unwrap(); let (param_env, ty) = query.into_parts(); if icx.layout_depth > rec_limit { diff --git a/src/librustc_middle/ty/query/on_disk_cache.rs b/src/librustc_middle/ty/query/on_disk_cache.rs index 71c2c24cc0a9f..4eae06742d9d3 100644 --- a/src/librustc_middle/ty/query/on_disk_cache.rs +++ b/src/librustc_middle/ty/query/on_disk_cache.rs @@ -6,7 +6,7 @@ use crate::ty::context::TyCtxt; use crate::ty::{self, Ty}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, Once}; +use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; @@ -49,7 +49,7 @@ pub struct OnDiskCache<'sess> { current_diagnostics: Lock>>, prev_cnums: Vec<(u32, String, CrateDisambiguator)>, - cnum_map: Once>>, + cnum_map: OnceCell>>, source_map: &'sess SourceMap, file_index_to_stable_id: FxHashMap, @@ -128,7 +128,7 @@ impl<'sess> OnDiskCache<'sess> { file_index_to_stable_id: footer.file_index_to_stable_id, file_index_to_file: Default::default(), prev_cnums: footer.prev_cnums, - cnum_map: Once::new(), + cnum_map: OnceCell::new(), source_map: sess.source_map(), current_diagnostics: Default::default(), query_result_index: footer.query_result_index.into_iter().collect(), @@ -144,7 +144,7 @@ impl<'sess> OnDiskCache<'sess> { file_index_to_stable_id: Default::default(), file_index_to_file: Default::default(), prev_cnums: vec![], - cnum_map: Once::new(), + cnum_map: OnceCell::new(), source_map, current_diagnostics: Default::default(), query_result_index: Default::default(), @@ -370,14 +370,14 @@ impl<'sess> OnDiskCache<'sess> { { let pos = index.get(&dep_node_index).cloned()?; - // Initialize `cnum_map` using the value from the thread that finishes the closure first. - self.cnum_map.init_nonlocking_same(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..])); + let cnum_map = + self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..])); let mut decoder = CacheDecoder { tcx, opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()), source_map: self.source_map, - cnum_map: self.cnum_map.get(), + cnum_map, synthetic_syntax_contexts: &self.synthetic_syntax_contexts, file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 0637ebf959e5a..fd5e0632a2c10 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -89,7 +89,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( InterpCx::new( tcx.at(span), param_env, - CompileTimeInterpreter::new(*tcx.sess.const_eval_limit.get()), + CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), MemoryExtra { can_access_statics }, ) } @@ -303,7 +303,7 @@ pub fn const_eval_raw_provider<'tcx>( let mut ecx = InterpCx::new( tcx.at(span), key.param_env, - CompileTimeInterpreter::new(*tcx.sess.const_eval_limit.get()), + CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), MemoryExtra { can_access_statics: is_static }, ); diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index eba4dd336ade2..4f91257e2ef83 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -651,7 +651,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { M::after_stack_push(self)?; info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance); - if self.stack().len() > *self.tcx.sess.recursion_limit.get() { + if self.stack().len() > self.tcx.sess.recursion_limit() { throw_exhaust!(StackFrameLimitReached) } else { Ok(()) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 925b8d329668f..081f6435d9db9 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -430,7 +430,7 @@ fn check_recursion_limit<'tcx>( // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. - if adjusted_recursion_depth > *tcx.sess.recursion_limit.get() { + if adjusted_recursion_depth > tcx.sess.recursion_limit() { let error = format!("reached the recursion limit while instantiating `{}`", instance); if let Some(def_id) = def_id.as_local() { let hir_id = tcx.hir().as_local_hir_id(def_id); @@ -463,8 +463,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // which means that rustc basically hangs. // // Bail out in these cases to avoid that bad user experience. - let type_length_limit = *tcx.sess.type_length_limit.get(); - if type_length > type_length_limit { + if type_length > tcx.sess.type_length_limit() { // The instance name is already known to be too long for rustc. // Show only the first and last 32 characters to avoid blasting // the user's terminal with thousands of lines of type-name. diff --git a/src/librustc_passes/entry.rs b/src/librustc_passes/entry.rs index d2f1d11256bf2..e0ad0ac77476f 100644 --- a/src/librustc_passes/entry.rs +++ b/src/librustc_passes/entry.rs @@ -51,7 +51,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> { assert_eq!(cnum, LOCAL_CRATE); - let any_exe = tcx.sess.crate_types.borrow().iter().any(|ty| *ty == CrateType::Executable); + let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable); if !any_exe { // No need to find a main function. return None; diff --git a/src/librustc_passes/reachable.rs b/src/librustc_passes/reachable.rs index 7c169d6813282..cac71b3836c54 100644 --- a/src/librustc_passes/reachable.rs +++ b/src/librustc_passes/reachable.rs @@ -376,7 +376,7 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, crate_num: CrateNum) -> &'tcx HirIdSet let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let any_library = - tcx.sess.crate_types.borrow().iter().any(|ty| { + tcx.sess.crate_types().iter().any(|ty| { *ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro }); let mut reachable_context = ReachableContext { diff --git a/src/librustc_passes/weak_lang_items.rs b/src/librustc_passes/weak_lang_items.rs index 8a581626862a2..96ec23692df51 100644 --- a/src/librustc_passes/weak_lang_items.rs +++ b/src/librustc_passes/weak_lang_items.rs @@ -37,7 +37,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { // We only need to check for the presence of weak lang items if we're // emitting something that's not an rlib. - let needs_check = tcx.sess.crate_types.borrow().iter().any(|kind| match *kind { + let needs_check = tcx.sess.crate_types().iter().any(|kind| match *kind { CrateType::Dylib | CrateType::ProcMacro | CrateType::Cdylib diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 43fd2b1853011..3bd68a9c656ce 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -87,7 +87,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { pub fn compilation_output(&self, crate_name: &str) -> PathBuf { let sess = &self.tcx.sess; // Save-analysis is emitted per whole session, not per each crate type - let crate_type = sess.crate_types.borrow()[0]; + let crate_type = sess.crate_types()[0]; let outputs = &*self.tcx.output_filenames(LOCAL_CRATE); if outputs.outputs.contains_key(&OutputType::Metadata) { @@ -987,8 +987,7 @@ impl<'a> DumpHandler<'a> { error!("Could not create directory {}: {}", root_path.display(), e); } - let executable = - sess.crate_types.borrow().iter().any(|ct| *ct == CrateType::Executable); + let executable = sess.crate_types().iter().any(|ct| *ct == CrateType::Executable); let mut out_name = if executable { String::new() } else { "lib".to_owned() }; out_name.push_str(&self.cratename); out_name.push_str(&sess.opts.cg.extra_filename); diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs index 69d3e99b7458e..746e3536ce908 100644 --- a/src/librustc_session/parse.rs +++ b/src/librustc_session/parse.rs @@ -4,7 +4,7 @@ use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId}; use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::{Lock, Lrc, Once}; +use rustc_data_structures::sync::{Lock, Lrc, OnceCell}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{error_code, Applicability, DiagnosticBuilder}; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; @@ -130,7 +130,7 @@ pub struct ParseSess { /// operation token that followed it, but that the parser cannot identify without further /// analysis. pub ambiguous_block_expr_parse: Lock>, - pub injected_crate_name: Once, + pub injected_crate_name: OnceCell, pub gated_spans: GatedSpans, pub symbol_gallery: SymbolGallery, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. @@ -156,7 +156,7 @@ impl ParseSess { source_map, buffered_lints: Lock::new(vec![]), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - injected_crate_name: Once::new(), + injected_crate_name: OnceCell::new(), gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), reached_eof: Lock::new(false), diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 143401dd3b622..f2f02cb649463 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::jobserver::{self, Client}; use rustc_data_structures::profiling::{duration_to_secs_str, SelfProfiler, SelfProfilerRef}; use rustc_data_structures::sync::{ - self, AtomicU64, AtomicUsize, Lock, Lrc, Once, OneThread, Ordering, Ordering::SeqCst, + self, AtomicU64, AtomicUsize, Lock, Lrc, OnceCell, OneThread, Ordering, Ordering::SeqCst, }; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; @@ -77,25 +77,25 @@ pub struct Session { /// (sub)diagnostics that have been set once, but should not be set again, /// in order to avoid redundantly verbose output (Issue #24690, #44953). pub one_time_diagnostics: Lock, String)>>, - pub crate_types: Once>, + crate_types: OnceCell>, /// The `crate_disambiguator` is constructed out of all the `-C metadata` /// arguments passed to the compiler. Its value together with the crate-name /// forms a unique global identifier for the crate. It is used to allow /// multiple crates with the same name to coexist. See the /// `rustc_codegen_llvm::back::symbol_names` module for more information. - pub crate_disambiguator: Once, + pub crate_disambiguator: OnceCell, - features: Once, + features: OnceCell, /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. - pub recursion_limit: Once, + pub recursion_limit: OnceCell, /// The maximum length of types during monomorphization. - pub type_length_limit: Once, + pub type_length_limit: OnceCell, /// The maximum blocks a const expression can evaluate. - pub const_eval_limit: Once, + pub const_eval_limit: OnceCell, incr_comp_session: OneThread>, /// Used for incremental compilation tests. Will only be populated if @@ -244,7 +244,27 @@ impl Session { } pub fn local_crate_disambiguator(&self) -> CrateDisambiguator { - *self.crate_disambiguator.get() + self.crate_disambiguator.get().copied().unwrap() + } + + pub fn crate_types(&self) -> &[CrateType] { + self.crate_types.get().unwrap().as_slice() + } + + pub fn init_crate_types(&self, crate_types: Vec) { + self.crate_types.set(crate_types).expect("`crate_types` was initialized twice") + } + + pub fn recursion_limit(&self) -> usize { + self.recursion_limit.get().copied().unwrap() + } + + pub fn type_length_limit(&self) -> usize { + self.type_length_limit.get().copied().unwrap() + } + + pub fn const_eval_limit(&self) -> usize { + self.const_eval_limit.get().copied().unwrap() } pub fn struct_span_warn>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'_> { @@ -500,11 +520,14 @@ impl Session { /// dependency tracking. Use tcx.features() instead. #[inline] pub fn features_untracked(&self) -> &rustc_feature::Features { - self.features.get() + self.features.get().unwrap() } pub fn init_features(&self, features: rustc_feature::Features) { - self.features.set(features); + match self.features.set(features) { + Ok(()) => {} + Err(_) => panic!("`features` was initialized twice"), + } } /// Calculates the flavor of LTO to use for this compilation. @@ -1208,12 +1231,12 @@ pub fn build_session_with_source_map( local_crate_source_file, working_dir, one_time_diagnostics: Default::default(), - crate_types: Once::new(), - crate_disambiguator: Once::new(), - features: Once::new(), - recursion_limit: Once::new(), - type_length_limit: Once::new(), - const_eval_limit: Once::new(), + crate_types: OnceCell::new(), + crate_disambiguator: OnceCell::new(), + features: OnceCell::new(), + recursion_limit: OnceCell::new(), + type_length_limit: OnceCell::new(), + const_eval_limit: OnceCell::new(), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), cgu_reuse_tracker, prof, diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 0760bd523b7c3..50a59469d8530 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1875,7 +1875,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { - let current_limit = self.tcx.sess.recursion_limit.get(); + let current_limit = self.tcx.sess.recursion_limit(); let suggested_limit = current_limit * 2; err.help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 9b63cbdd83cac..914485fd408fc 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -332,7 +332,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { Reveal::UserFacing => ty, Reveal::All => { - let recursion_limit = *self.tcx().sess.recursion_limit.get(); + let recursion_limit = self.tcx().sess.recursion_limit(); if self.depth >= recursion_limit { let obligation = Obligation::with_depth( self.cause.clone(), @@ -520,7 +520,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ); // But for now, let's classify this as an overflow: - let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); + let recursion_limit = selcx.tcx().sess.recursion_limit(); let obligation = Obligation::with_depth(cause, recursion_limit, param_env, projection_ty); selcx.infcx().report_overflow_error(&obligation, false); @@ -814,7 +814,7 @@ fn project_type<'cx, 'tcx>( ) -> Result, ProjectionTyError<'tcx>> { debug!("project(obligation={:?})", obligation); - let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); + let recursion_limit = selcx.tcx().sess.recursion_limit(); if obligation.recursion_depth >= recursion_limit { debug!("project: overflow!"); return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index 3b985a4b150fa..008ca8d526dd3 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -108,7 +108,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { Reveal::UserFacing => ty, Reveal::All => { - let recursion_limit = *self.tcx().sess.recursion_limit.get(); + let recursion_limit = self.tcx().sess.recursion_limit(); if self.anon_depth >= recursion_limit { let obligation = Obligation::with_depth( self.cause.clone(), diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 6110d6470df90..b402aba65cdb7 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -919,8 +919,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &Obligation<'tcx, T>, error_obligation: &Obligation<'tcx, V>, ) -> Result<(), OverflowError> { - let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { + if obligation.recursion_depth >= self.infcx.tcx.sess.recursion_limit() { match self.query_mode { TraitQueryMode::Standard => { self.infcx().report_overflow_error(error_obligation, true); diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 08475d6a09db1..fb9c0d7f99013 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -163,7 +163,7 @@ fn dtorck_constraint_for_ty<'tcx>( ) -> Result<(), NoSolution> { debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); - if depth >= *tcx.sess.recursion_limit.get() { + if depth >= tcx.sess.recursion_limit() { constraints.overflows.push(ty); return Ok(()); } diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs index 97994b465b54c..e94a47f079a63 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/src/librustc_ty/needs_drop.rs @@ -43,14 +43,13 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { ) -> Self { let mut seen_tys = FxHashSet::default(); seen_tys.insert(ty); - let recursion_limit = *tcx.sess.recursion_limit.get(); Self { tcx, param_env, seen_tys, query_ty: ty, unchecked_tys: vec![(ty, 0)], - recursion_limit, + recursion_limit: tcx.sess.recursion_limit(), adt_components, } } diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 8ca0861090605..d4c01a82e0aa5 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { return Some((self.cur_ty, 0)); } - if self.steps.len() >= *tcx.sess.recursion_limit.get() { + if self.steps.len() >= tcx.sess.recursion_limit() { if !self.silence_errors { report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty); } @@ -236,7 +236,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { // We've reached the recursion limit, error gracefully. - let suggested_limit = *tcx.sess.recursion_limit.get() * 2; + let suggested_limit = tcx.sess.recursion_limit() * 2; let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 5300fd2215b39..3ad3d5aee4d4a 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -71,7 +71,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, attrs: &[ast::Attribute] fn is_executable(cx: &LateContext<'_, '_>) -> bool { use rustc_session::config::CrateType; - cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| match t { + cx.tcx.sess.crate_types().iter().any(|t: &CrateType| match t { CrateType::Executable => true, _ => false, }) From f17e2c93a69443c93aa42e0df0a119d35c4d49d9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 May 2020 21:56:33 -0700 Subject: [PATCH 175/695] Use `OnceCell` for predecessor cache --- src/librustc_middle/mir/predecessors.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/librustc_middle/mir/predecessors.rs b/src/librustc_middle/mir/predecessors.rs index 9508365886aa7..36e92c71c07f4 100644 --- a/src/librustc_middle/mir/predecessors.rs +++ b/src/librustc_middle/mir/predecessors.rs @@ -1,7 +1,7 @@ //! Lazily compute the reverse control-flow graph for the MIR. use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{Lock, Lrc}; +use rustc_data_structures::sync::OnceCell; use rustc_index::vec::IndexVec; use rustc_serialize as serialize; use smallvec::SmallVec; @@ -13,13 +13,13 @@ pub type Predecessors = IndexVec>; #[derive(Clone, Debug)] pub(super) struct PredecessorCache { - cache: Lock>>, + cache: OnceCell, } impl PredecessorCache { #[inline] pub(super) fn new() -> Self { - PredecessorCache { cache: Lock::new(None) } + PredecessorCache { cache: OnceCell::new() } } /// Invalidates the predecessor cache. @@ -27,23 +27,19 @@ impl PredecessorCache { /// Invalidating the predecessor cache requires mutating the MIR, which in turn requires a /// unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all /// callers of `invalidate` have a unique reference to the MIR and thus to the predecessor - /// cache. This means we don't actually need to take a lock when `invalidate` is called. + /// cache. This means we never need to do synchronization when `invalidate` is called. #[inline] pub(super) fn invalidate(&mut self) { - *self.cache.get_mut() = None; + self.cache = OnceCell::new(); } - /// Returns a ref-counted smart pointer containing the predecessor graph for this MIR. - /// - /// We use ref-counting instead of a mapped `LockGuard` here to ensure that the lock for - /// `cache` is only held inside this function. As long as no other locks are taken while - /// computing the predecessor graph, deadlock is impossible. + /// Returns the the predecessor graph for this MIR. #[inline] pub(super) fn compute( &self, basic_blocks: &IndexVec>, - ) -> Lrc { - Lrc::clone(self.cache.lock().get_or_insert_with(|| { + ) -> &Predecessors { + self.cache.get_or_init(|| { let mut preds = IndexVec::from_elem(SmallVec::new(), basic_blocks); for (bb, data) in basic_blocks.iter_enumerated() { if let Some(term) = &data.terminator { @@ -53,8 +49,8 @@ impl PredecessorCache { } } - Lrc::new(preds) - })) + preds + }) } } From 307153e611433f9224224a4511b6ea4f362ffe28 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 16 May 2020 11:26:21 -0700 Subject: [PATCH 176/695] Switch to non-doc comment --- src/librustc_middle/mir/predecessors.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_middle/mir/predecessors.rs b/src/librustc_middle/mir/predecessors.rs index 36e92c71c07f4..7508c0239397f 100644 --- a/src/librustc_middle/mir/predecessors.rs +++ b/src/librustc_middle/mir/predecessors.rs @@ -23,13 +23,13 @@ impl PredecessorCache { } /// Invalidates the predecessor cache. - /// - /// Invalidating the predecessor cache requires mutating the MIR, which in turn requires a - /// unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all - /// callers of `invalidate` have a unique reference to the MIR and thus to the predecessor - /// cache. This means we never need to do synchronization when `invalidate` is called. #[inline] pub(super) fn invalidate(&mut self) { + // Invalidating the predecessor cache requires mutating the MIR, which in turn requires a + // unique reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all + // callers of `invalidate` have a unique reference to the MIR and thus to the predecessor + // cache. This means we never need to do synchronization when `invalidate` is called, we can + // simply reinitialize the `OnceCell`. self.cache = OnceCell::new(); } From b3a690f5a1791dae79ab3dbbb3252e05f318adeb Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 15 May 2020 21:44:28 -0700 Subject: [PATCH 177/695] Use `OnceCell` instead of `Once` --- clippy_lints/src/missing_inline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 5300fd2215b39..3ad3d5aee4d4a 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -71,7 +71,7 @@ fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, attrs: &[ast::Attribute] fn is_executable(cx: &LateContext<'_, '_>) -> bool { use rustc_session::config::CrateType; - cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| match t { + cx.tcx.sess.crate_types().iter().any(|t: &CrateType| match t { CrateType::Executable => true, _ => false, }) From 730c6f3e57a4068547d2d08e7a84efea215cd1ee Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 27 Apr 2020 12:28:24 -0700 Subject: [PATCH 178/695] Preserve substitutions when trying to prove trait obligation `mk_obligation_for_def_id` is only correct if the trait and self type do not have any substitutions. Use a different method, `mk_trait_obligation_with_new_self_ty` that is more clear about what is happening. --- .../traits/error_reporting/mod.rs | 27 +++++++----- .../traits/error_reporting/suggestions.rs | 41 +++++++++---------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 2aef8aaf0e303..20de0b786ed70 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1000,12 +1000,11 @@ trait InferCtxtPrivExt<'tcx> { trait_ref: &ty::PolyTraitRef<'tcx>, ); - fn mk_obligation_for_def_id( + fn mk_trait_obligation_with_new_self_ty( &self, - def_id: DefId, - output_ty: Ty<'tcx>, - cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx>; fn maybe_report_ambiguity( @@ -1380,16 +1379,22 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } } - fn mk_obligation_for_def_id( + fn mk_trait_obligation_with_new_self_ty( &self, - def_id: DefId, - output_ty: Ty<'tcx>, - cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, + trait_ref: &ty::PolyTraitRef<'tcx>, + new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx> { - let new_trait_ref = - ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; - Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate(self.tcx)) + let trait_ref = trait_ref.map_bound_ref(|tr| ty::TraitRef { + substs: self.tcx.mk_substs_trait(new_self_ty, &tr.substs[1..]), + ..*tr + }); + + Obligation::new( + ObligationCause::dummy(), + param_env, + trait_ref.without_const().to_predicate(self.tcx), + ) } fn maybe_report_ambiguity( diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 0760bd523b7c3..6712ddf0ae544 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -532,14 +532,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; let msg = format!("use parentheses to call the {}", callable); - let obligation = self.mk_obligation_for_def_id( - trait_ref.def_id(), - output_ty.skip_binder(), - obligation.cause.clone(), + let new_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, + trait_ref, + output_ty.skip_binder(), ); - match self.evaluate_obligation(&obligation) { + match self.evaluate_obligation(&new_obligation) { Ok( EvaluationResult::EvaluatedToOk | EvaluationResult::EvaluatedToOkModuloRegions @@ -694,7 +693,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, trait_ref: &ty::Binder>, ) { - let trait_ref = trait_ref.skip_binder(); let span = obligation.cause.span; if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -705,17 +703,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - let mut trait_type = trait_ref.self_ty(); + let mut suggested_ty = trait_ref.self_ty(); for refs_remaining in 0..refs_number { - if let ty::Ref(_, t_type, _) = trait_type.kind { - trait_type = t_type; + if let ty::Ref(_, inner_ty, _) = suggested_ty.kind { + suggested_ty = inner_ty; - let new_obligation = self.mk_obligation_for_def_id( - trait_ref.def_id, - trait_type, - ObligationCause::dummy(), + let new_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, + trait_ref, + suggested_ty, ); if self.predicate_may_hold(&new_obligation) { @@ -782,20 +779,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - let trait_type = match mutability { + let suggested_ty = match mutability { hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type), hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type), }; - let new_obligation = self.mk_obligation_for_def_id( - trait_ref.skip_binder().def_id, - trait_type, - ObligationCause::dummy(), + let new_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, + &trait_ref, + suggested_ty, ); - - if self.evaluate_obligation_no_overflow(&new_obligation).must_apply_modulo_regions() - { + let suggested_ty_would_satisfy_obligation = self + .evaluate_obligation_no_overflow(&new_obligation) + .must_apply_modulo_regions(); + if suggested_ty_would_satisfy_obligation { let sp = self .tcx .sess @@ -812,7 +809,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.note(&format!( "`{}` is implemented for `{:?}`, but not for `{:?}`", trait_ref.print_only_trait_path(), - trait_type, + suggested_ty, trait_ref.skip_binder().self_ty(), )); } From 8ea828be2f1266578121a2dfe76693115e8f03ff Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 27 Apr 2020 12:34:00 -0700 Subject: [PATCH 179/695] Add regression test for #71394 --- src/test/ui/suggestions/issue-71394-no-from-impl.rs | 5 +++++ .../ui/suggestions/issue-71394-no-from-impl.stderr | 11 +++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/test/ui/suggestions/issue-71394-no-from-impl.rs create mode 100644 src/test/ui/suggestions/issue-71394-no-from-impl.stderr diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.rs b/src/test/ui/suggestions/issue-71394-no-from-impl.rs new file mode 100644 index 0000000000000..9ffcc3f7bc1c1 --- /dev/null +++ b/src/test/ui/suggestions/issue-71394-no-from-impl.rs @@ -0,0 +1,5 @@ +fn main() { + let data: &[u8] = &[0; 10]; + let _: &[i8] = data.into(); + //~^ ERROR the trait bound `&[i8]: std::convert::From<&[u8]>` is not satisfied +} diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr new file mode 100644 index 0000000000000..84c73c2f67e70 --- /dev/null +++ b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `&[i8]: std::convert::From<&[u8]>` is not satisfied + --> $DIR/issue-71394-no-from-impl.rs:3:25 + | +LL | let _: &[i8] = data.into(); + | ^^^^ the trait `std::convert::From<&[u8]>` is not implemented for `&[i8]` + | + = note: required because of the requirements on the impl of `std::convert::Into<&[i8]>` for `&[u8]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 4d9e9c6d4ec11dcfa1e89040f894c9400828a9fb Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 27 Apr 2020 12:34:25 -0700 Subject: [PATCH 180/695] Bless other example of #71394 --- src/test/ui/suggestions/into-str.stderr | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index 7414a7cc24c92..f7affdbf1b408 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -8,7 +8,6 @@ LL | foo(String::new()); | ^^^ the trait `std::convert::From` is not implemented for `&str` | = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix - = note: `std::convert::From` is implemented for `&mut str`, but not for `&str` = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` error: aborting due to previous error From d2bacb18d2bf9eadca86fe7c1483e38ce774750e Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Tue, 28 Apr 2020 13:04:48 -0700 Subject: [PATCH 181/695] Ensure that `new_self_ty` has no escaping bound vars Otherwise inserting it to the `Binder` used by `trait_ref` would cause problems. This is just to be extra carefult: we aren't going to start recommending that the user start using HKTs anytime soon. --- src/librustc_trait_selection/traits/error_reporting/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 20de0b786ed70..c59abd3602116 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1385,6 +1385,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: &ty::PolyTraitRef<'tcx>, new_self_ty: Ty<'tcx>, ) -> PredicateObligation<'tcx> { + assert!(!new_self_ty.has_escaping_bound_vars()); + let trait_ref = trait_ref.map_bound_ref(|tr| ty::TraitRef { substs: self.tcx.mk_substs_trait(new_self_ty, &tr.substs[1..]), ..*tr From 7278e29592b96207c755bedcc846b64a93aa9281 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 18 May 2020 11:18:41 -0700 Subject: [PATCH 182/695] Document invariants of `mk_trait_obligation_with_new_self_ty` --- src/librustc_trait_selection/traits/error_reporting/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index c59abd3602116..b1c6815c7414f 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1000,6 +1000,10 @@ trait InferCtxtPrivExt<'tcx> { trait_ref: &ty::PolyTraitRef<'tcx>, ); + /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the + /// `trait_ref`. + /// + /// For this to work, `new_self_ty` must have no escaping bound variables. fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, From f99519bebb2cdd90379bb2b07a0cfdeeb5d2d469 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 18 May 2020 11:18:55 -0700 Subject: [PATCH 183/695] Bail out if `output_ty` has bound variables --- .../traits/error_reporting/suggestions.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 6712ddf0ae544..ead857ee88745 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -532,11 +532,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; let msg = format!("use parentheses to call the {}", callable); - let new_obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - trait_ref, - output_ty.skip_binder(), - ); + // `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound + // variables, so bail out if we have any. + let output_ty = match output_ty.no_bound_vars() { + Some(ty) => ty, + None => return, + }; + + let new_obligation = + self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_ref, output_ty); match self.evaluate_obligation(&new_obligation) { Ok( From 1fad3b7a0535c4a4da046170d4080e0cd214ee42 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 18 May 2020 11:45:55 -0700 Subject: [PATCH 184/695] Use `mk_trait_obligation_with_new_self_ty` for new suggestion --- .../traits/error_reporting/suggestions.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index ead857ee88745..db29f6f3bc60b 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1892,7 +1892,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span: Span, ) { debug!( - "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}", + "suggest_await_before_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}", obligation, span, trait_ref, @@ -1947,16 +1947,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); debug!( - "suggest_await_befor_try: normalized_projection_type {:?}", + "suggest_await_before_try: normalized_projection_type {:?}", self.resolve_vars_if_possible(&normalized_ty) ); - let try_obligation = self.mk_obligation_for_def_id( - trait_ref.def_id(), - normalized_ty, - obligation.cause.clone(), + let try_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, + trait_ref, + normalized_ty, ); - debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation); + debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation); if self.predicate_may_hold(&try_obligation) && impls_future { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { if snippet.ends_with('?') { From d277904582d530feb4701dc76508fdf473cce8f4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 22 May 2020 16:57:25 -0400 Subject: [PATCH 185/695] Remove `macro_defs` map We store store the `DefId` directly in `ExpnData`. This will allow us to serialize `ExpnData` in PR #72121 without needing to manage a side table. --- src/librustc_ast_lowering/lib.rs | 2 +- src/librustc_expand/base.rs | 10 +++++++++- src/librustc_expand/expand.rs | 1 + src/librustc_resolve/build_reduced_graph.rs | 4 ++-- src/librustc_resolve/lib.rs | 11 +++-------- src/librustc_resolve/macros.rs | 13 ++++++++---- src/librustc_span/hygiene.rs | 22 ++++++++++++++++++--- 7 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 2cf81af04166c..c67829f7a08e6 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -688,7 +688,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> Span { span.fresh_expansion(ExpnData { allow_internal_unstable, - ..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) + ..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition(), None) }) } diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index fe5bf6f82c6d3..0137080938fdd 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -13,6 +13,7 @@ use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, ErrorReported}; use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::parse::ParseSess; +use rustc_span::def_id::DefId; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind}; use rustc_span::source_map::SourceMap; @@ -857,7 +858,13 @@ impl SyntaxExtension { SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition) } - pub fn expn_data(&self, parent: ExpnId, call_site: Span, descr: Symbol) -> ExpnData { + pub fn expn_data( + &self, + parent: ExpnId, + call_site: Span, + descr: Symbol, + macro_def_id: Option, + ) -> ExpnData { ExpnData { kind: ExpnKind::Macro(self.macro_kind(), descr), parent, @@ -867,6 +874,7 @@ impl SyntaxExtension { allow_internal_unsafe: self.allow_internal_unsafe, local_inner_macros: self.local_inner_macros, edition: self.edition, + macro_def_id, } } } diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 485c5147d2c26..b505302f62501 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -988,6 +988,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ExpnKind::Macro(MacroKind::Attr, sym::derive), item.span(), self.cx.parse_sess.edition, + None, ) }), _ => None, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 988ec3d4374e0..c32b823fe73b2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -126,8 +126,8 @@ impl<'a> Resolver<'a> { } crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { - let def_id = match self.macro_defs.get(&expn_id) { - Some(def_id) => *def_id, + let def_id = match expn_id.expn_data().macro_def_id { + Some(def_id) => def_id, None => return self.ast_transform_scopes.get(&expn_id).unwrap_or(&self.graph_root), }; if let Some(id) = self.definitions.as_local_node_id(def_id) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bfb7f081fc333..34368a07071fe 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -922,7 +922,6 @@ pub struct Resolver<'a> { dummy_ext_bang: Lrc, dummy_ext_derive: Lrc, non_macro_attrs: [Lrc; 2], - macro_defs: FxHashMap, local_macro_def_scopes: FxHashMap>, ast_transform_scopes: FxHashMap>, unused_macros: NodeMap, @@ -1152,9 +1151,6 @@ impl<'a> Resolver<'a> { let mut invocation_parent_scopes = FxHashMap::default(); invocation_parent_scopes.insert(ExpnId::root(), ParentScope::module(graph_root)); - let mut macro_defs = FxHashMap::default(); - macro_defs.insert(ExpnId::root(), root_def_id); - let features = session.features_untracked(); let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition())); @@ -1229,7 +1225,6 @@ impl<'a> Resolver<'a> { invocation_parent_scopes, output_macro_rules_scopes: Default::default(), helper_attrs: Default::default(), - macro_defs, local_macro_def_scopes: FxHashMap::default(), name_already_seen: FxHashMap::default(), potentially_unused_imports: Vec::new(), @@ -1335,8 +1330,8 @@ impl<'a> Resolver<'a> { fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId { loop { - match self.macro_defs.get(&ctxt.outer_expn()) { - Some(&def_id) => return def_id, + match ctxt.outer_expn().expn_data().macro_def_id { + Some(def_id) => return def_id, None => ctxt.remove_mark(), }; } @@ -1820,7 +1815,7 @@ impl<'a> Resolver<'a> { && module.expansion.is_descendant_of(parent.expansion) { // The macro is a proc macro derive - if let Some(&def_id) = self.macro_defs.get(&module.expansion) { + if let Some(def_id) = module.expansion.expn_data().macro_def_id { if let Some(ext) = self.get_macro_by_def_id(def_id) { if !ext.is_builtin && ext.macro_kind() == MacroKind::Derive { if parent.expansion.outer_expn_is_descendant_of(span.ctxt()) { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 1b6268dc8cbcf..7027c82626787 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -186,6 +186,7 @@ impl<'a> base::Resolver for Resolver<'a> { call_site, self.session.edition(), features.into(), + None, ))); let parent_scope = if let Some(module_id) = parent_module_id { @@ -290,13 +291,17 @@ impl<'a> base::Resolver for Resolver<'a> { let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?; let span = invoc.span(); - invoc_id.set_expn_data(ext.expn_data(parent_scope.expansion, span, fast_print_path(path))); - - if let Res::Def(_, def_id) = res { + invoc_id.set_expn_data(ext.expn_data( + parent_scope.expansion, + span, + fast_print_path(path), + res.opt_def_id(), + )); + + if let Res::Def(_, _) = res { if after_derive { self.session.span_err(span, "macro attributes must be placed before `#[derive]`"); } - self.macro_defs.insert(invoc_id, def_id); let normal_module_def_id = self.macro_def_scope(invoc_id).normal_ancestor_id; self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id); } diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs index 23c3dccb130f6..c0fb84e741f4a 100644 --- a/src/librustc_span/hygiene.rs +++ b/src/librustc_span/hygiene.rs @@ -25,6 +25,7 @@ // because getting it wrong can lead to nested `HygieneData::with` calls that // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) +use crate::def_id::{DefId, CRATE_DEF_INDEX}; use crate::edition::Edition; use crate::symbol::{kw, sym, Symbol}; use crate::GLOBALS; @@ -155,7 +156,12 @@ crate struct HygieneData { impl HygieneData { crate fn new(edition: Edition) -> Self { HygieneData { - expn_data: vec![Some(ExpnData::default(ExpnKind::Root, DUMMY_SP, edition))], + expn_data: vec![Some(ExpnData::default( + ExpnKind::Root, + DUMMY_SP, + edition, + Some(DefId::local(CRATE_DEF_INDEX)), + ))], syntax_context_data: vec![SyntaxContextData { outer_expn: ExpnId::root(), outer_transparency: Transparency::Opaque, @@ -673,11 +679,19 @@ pub struct ExpnData { pub local_inner_macros: bool, /// Edition of the crate in which the macro is defined. pub edition: Edition, + /// The `DefId` of the macro being invoked, + /// if this `ExpnData` corresponds to a macro invocation + pub macro_def_id: Option, } impl ExpnData { /// Constructs expansion data with default properties. - pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnData { + pub fn default( + kind: ExpnKind, + call_site: Span, + edition: Edition, + macro_def_id: Option, + ) -> ExpnData { ExpnData { kind, parent: ExpnId::root(), @@ -687,6 +701,7 @@ impl ExpnData { allow_internal_unsafe: false, local_inner_macros: false, edition, + macro_def_id, } } @@ -695,10 +710,11 @@ impl ExpnData { call_site: Span, edition: Edition, allow_internal_unstable: Lrc<[Symbol]>, + macro_def_id: Option, ) -> ExpnData { ExpnData { allow_internal_unstable: Some(allow_internal_unstable), - ..ExpnData::default(kind, call_site, edition) + ..ExpnData::default(kind, call_site, edition, macro_def_id) } } From a9199de34d0ad78fe1ff0d072f6bd5c01906bdb3 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Sat, 23 May 2020 00:16:17 +0300 Subject: [PATCH 186/695] Merge spans for the suggestion --- src/librustc_typeck/check/callee.rs | 17 +++++++++++------ src/test/ui/error-codes/E0040.stderr | 8 ++++---- .../ui/explicit/explicit-call-to-dtor.stderr | 8 ++++---- .../explicit-call-to-supertrait-dtor.stderr | 8 ++++---- src/test/ui/illegal-ufcs-drop.stderr | 2 +- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 4c31363f2c084..a32174a83337d 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -35,13 +35,18 @@ pub fn check_legal_trait_for_method_call( .and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok()) .unwrap_or_default(); - let (suggestion, applicability) = if snippet.is_empty() { - (snippet, Applicability::Unspecified) - } else { - (format!("drop({})", snippet), Applicability::MachineApplicable) - }; + let suggestion = + if snippet.is_empty() { "drop".to_string() } else { format!("drop({})", snippet) }; + + let suggestion_span = + receiver.and_then(|s| tcx.sess.source_map().merge_spans(s, span)).unwrap_or(span); - err.span_suggestion(span, "consider using `drop` function", suggestion, applicability); + err.span_suggestion( + suggestion_span, + "consider using `drop` function", + suggestion, + Applicability::MaybeIncorrect, + ); err.emit(); } diff --git a/src/test/ui/error-codes/E0040.stderr b/src/test/ui/error-codes/E0040.stderr index 69cf28b29704f..3b864d4ea4b2c 100644 --- a/src/test/ui/error-codes/E0040.stderr +++ b/src/test/ui/error-codes/E0040.stderr @@ -2,10 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/E0040.rs:13:7 | LL | x.drop(); - | ^^^^ - | | - | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(x)` + | --^^^^ + | | | + | | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(x)` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-dtor.stderr b/src/test/ui/explicit/explicit-call-to-dtor.stderr index 5ebe4ee4b90f8..33ce235b30fda 100644 --- a/src/test/ui/explicit/explicit-call-to-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-dtor.stderr @@ -2,10 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-dtor.rs:13:7 | LL | x.drop(); - | ^^^^ - | | - | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(x)` + | --^^^^ + | | | + | | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(x)` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr index cd3fb3119a5cf..2e7bfac71cd32 100644 --- a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -2,10 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-supertrait-dtor.rs:17:14 | LL | self.drop(); - | ^^^^ - | | - | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(self)` + | -----^^^^ + | | | + | | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(self)` error: aborting due to previous error diff --git a/src/test/ui/illegal-ufcs-drop.stderr b/src/test/ui/illegal-ufcs-drop.stderr index 922d50d259569..57c99739afd24 100644 --- a/src/test/ui/illegal-ufcs-drop.stderr +++ b/src/test/ui/illegal-ufcs-drop.stderr @@ -5,7 +5,7 @@ LL | Drop::drop(&mut Foo) | ^^^^^^^^^^ | | | explicit destructor calls not allowed - | help: consider using `drop` function + | help: consider using `drop` function: `drop` error: aborting due to previous error From e04baed0db5aa880f0b9fcdfcf9295159dd3ee01 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 23 May 2020 07:33:09 +0100 Subject: [PATCH 187/695] Fix ice-72487 --- src/librustc_target/asm/mod.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index 05aa85ecb7448..774146a679ab8 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -223,19 +223,19 @@ impl InlineAsmReg { name: Symbol, ) -> Result { // FIXME: use direct symbol comparison for register names - name.with(|name| { - Ok(match arch { - InlineAsmArch::X86 | InlineAsmArch::X86_64 => { - Self::X86(X86InlineAsmReg::parse(arch, has_feature, name)?) - } - InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, name)?), - InlineAsmArch::AArch64 => { - Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, name)?) - } - InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { - Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, name)?) - } - }) + // Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`. + let name = name.as_str(); + Ok(match arch { + InlineAsmArch::X86 | InlineAsmArch::X86_64 => { + Self::X86(X86InlineAsmReg::parse(arch, has_feature, &name)?) + } + InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, &name)?), + InlineAsmArch::AArch64 => { + Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, &name)?) + } + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { + Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?) + } }) } From 58fe05a124383d87ab3eaa3a2f754577954eb94a Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 23 May 2020 17:51:58 +0900 Subject: [PATCH 188/695] Add test for #69415 --- .../feature-gate-associated_type_bounds.rs | 3 ++ ...feature-gate-associated_type_bounds.stderr | 32 +++++++++---------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs index 0faa9090f4ebc..9bce274027ee0 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs @@ -1,3 +1,6 @@ +// compile-flags: -Zsave-analysis +// This is also a regression test for #69415 and the above flag is needed. + #![feature(untagged_unions)] trait Tr1 { type As1: Copy; } diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr index bfa59d83c82fa..7f2704e1bc371 100644 --- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.stderr @@ -1,5 +1,5 @@ error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:12:22 + --> $DIR/feature-gate-associated_type_bounds.rs:15:22 | LL | type A: Iterator; | ^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | type A: Iterator; = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:15:22 + --> $DIR/feature-gate-associated_type_bounds.rs:18:22 | LL | type B: Iterator; | ^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | type B: Iterator; = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:19:20 + --> $DIR/feature-gate-associated_type_bounds.rs:22:20 | LL | struct _St1> { | ^^^^^^^^ @@ -26,7 +26,7 @@ LL | struct _St1> { = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:26:18 + --> $DIR/feature-gate-associated_type_bounds.rs:29:18 | LL | enum _En1> { | ^^^^^^^^ @@ -35,7 +35,7 @@ LL | enum _En1> { = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:33:19 + --> $DIR/feature-gate-associated_type_bounds.rs:36:19 | LL | union _Un1> { | ^^^^^^^^ @@ -44,7 +44,7 @@ LL | union _Un1> { = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:40:37 + --> $DIR/feature-gate-associated_type_bounds.rs:43:37 | LL | type _TaWhere1 where T: Iterator = T; | ^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | type _TaWhere1 where T: Iterator = T; = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:43:22 + --> $DIR/feature-gate-associated_type_bounds.rs:46:22 | LL | fn _apit(_: impl Tr1) {} | ^^^^^^^^^ @@ -62,7 +62,7 @@ LL | fn _apit(_: impl Tr1) {} = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:45:26 + --> $DIR/feature-gate-associated_type_bounds.rs:48:26 | LL | fn _apit_dyn(_: &dyn Tr1) {} | ^^^^^^^^^ @@ -71,7 +71,7 @@ LL | fn _apit_dyn(_: &dyn Tr1) {} = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:48:24 + --> $DIR/feature-gate-associated_type_bounds.rs:51:24 | LL | fn _rpit() -> impl Tr1 { S1 } | ^^^^^^^^^ @@ -80,7 +80,7 @@ LL | fn _rpit() -> impl Tr1 { S1 } = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:51:31 + --> $DIR/feature-gate-associated_type_bounds.rs:54:31 | LL | fn _rpit_dyn() -> Box> { Box::new(S1) } | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | fn _rpit_dyn() -> Box> { Box::new(S1) } = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:54:23 + --> $DIR/feature-gate-associated_type_bounds.rs:57:23 | LL | const _cdef: impl Tr1 = S1; | ^^^^^^^^^ @@ -98,7 +98,7 @@ LL | const _cdef: impl Tr1 = S1; = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:60:24 + --> $DIR/feature-gate-associated_type_bounds.rs:63:24 | LL | static _sdef: impl Tr1 = S1; | ^^^^^^^^^ @@ -107,7 +107,7 @@ LL | static _sdef: impl Tr1 = S1; = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0658]: associated type bounds are unstable - --> $DIR/feature-gate-associated_type_bounds.rs:67:21 + --> $DIR/feature-gate-associated_type_bounds.rs:70:21 | LL | let _: impl Tr1 = S1; | ^^^^^^^^^ @@ -116,7 +116,7 @@ LL | let _: impl Tr1 = S1; = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-associated_type_bounds.rs:54:14 + --> $DIR/feature-gate-associated_type_bounds.rs:57:14 | LL | const _cdef: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ @@ -124,7 +124,7 @@ LL | const _cdef: impl Tr1 = S1; = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-associated_type_bounds.rs:60:15 + --> $DIR/feature-gate-associated_type_bounds.rs:63:15 | LL | static _sdef: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | static _sdef: impl Tr1 = S1; = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/feature-gate-associated_type_bounds.rs:67:12 + --> $DIR/feature-gate-associated_type_bounds.rs:70:12 | LL | let _: impl Tr1 = S1; | ^^^^^^^^^^^^^^^^^^^ From 47e35cb9bdcb4d2fd66595d566633e9444325ad4 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 23 May 2020 17:52:11 +0900 Subject: [PATCH 189/695] Add test for #72455 --- src/test/ui/issues/issue-72455.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/test/ui/issues/issue-72455.rs diff --git a/src/test/ui/issues/issue-72455.rs b/src/test/ui/issues/issue-72455.rs new file mode 100644 index 0000000000000..b6c3bb222876d --- /dev/null +++ b/src/test/ui/issues/issue-72455.rs @@ -0,0 +1,27 @@ +// check-pass + +pub trait ResultExt { + type Ok; + fn err_eprint_and_ignore(self) -> Option; +} + +impl ResultExt for std::result::Result +where + E: std::error::Error, +{ + type Ok = O; + fn err_eprint_and_ignore(self) -> Option + where + Self: , + { + match self { + Err(e) => { + eprintln!("{}", e); + None + } + Ok(o) => Some(o), + } + } +} + +fn main() {} From 647ae50ce69e1714faebc4e2a4d252536a5663d8 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 11:09:32 +0200 Subject: [PATCH 190/695] take predicates by value instead of by reference --- src/librustc_infer/infer/mod.rs | 8 ++++---- src/librustc_infer/infer/outlives/verify.rs | 7 ++++--- src/librustc_infer/traits/util.rs | 16 ++++++++-------- src/librustc_middle/ty/mod.rs | 12 +++--------- .../traits/auto_trait.rs | 4 ++-- .../traits/error_reporting/mod.rs | 12 ++++++------ src/librustc_trait_selection/traits/fulfill.rs | 4 ++-- src/librustc_trait_selection/traits/project.rs | 4 ++-- src/librustc_trait_selection/traits/select.rs | 14 +++++++------- src/librustc_trait_selection/traits/util.rs | 4 ++-- src/librustc_trait_selection/traits/wf.rs | 2 +- src/librustc_typeck/check/closure.rs | 11 +++++------ src/librustc_typeck/check/dropck.rs | 8 ++++---- src/librustc_typeck/check/wfcheck.rs | 4 ++-- .../impl_wf_check/min_specialization.rs | 15 ++++++--------- 15 files changed, 58 insertions(+), 67 deletions(-) diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 9c81a1153958b..09a90516e9197 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -1011,7 +1011,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - predicate: &ty::PolySubtypePredicate<'tcx>, + predicate: ty::PolySubtypePredicate<'tcx>, ) -> Option> { // Subtle: it's ok to skip the binder here and resolve because // `shallow_resolve` just ignores anything that is not a type @@ -1034,7 +1034,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some(self.commit_if_ok(|snapshot| { let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) = - self.replace_bound_vars_with_placeholders(predicate); + self.replace_bound_vars_with_placeholders(&predicate); let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; @@ -1047,11 +1047,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn region_outlives_predicate( &self, cause: &traits::ObligationCause<'tcx>, - predicate: &ty::PolyRegionOutlivesPredicate<'tcx>, + predicate: ty::PolyRegionOutlivesPredicate<'tcx>, ) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) = - self.replace_bound_vars_with_placeholders(predicate); + self.replace_bound_vars_with_placeholders(&predicate); let origin = SubregionOrigin::from_obligation_cause(cause, || { RelateRegionParamBound(cause.span) }); diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs index 5020dc4132cc3..cac1d2f050efc 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -223,7 +223,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // like `T` and `T::Item`. It may not work as well for things // like `>::Item`. let c_b = self.param_env.caller_bounds; - let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter()); + let param_bounds = + self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter().copied()); // Next, collect regions we scraped from the well-formedness // constraints in the fn signature. To do that, we walk the list @@ -334,10 +335,10 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn collect_outlives_from_predicate_list( &self, compare_ty: impl Fn(Ty<'tcx>) -> bool, - predicates: impl Iterator>>, + predicates: impl Iterator>, ) -> impl Iterator, ty::Region<'tcx>>> { predicates - .filter_map(|p| p.as_ref().to_opt_type_outlives()) + .filter_map(|p| p.to_opt_type_outlives()) .filter_map(|p| p.no_bound_vars()) .filter(move |p| compare_ty(p.0)) } diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 88fc1460475df..03f20c13068a8 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -8,7 +8,7 @@ use rustc_span::Span; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, - pred: &ty::Predicate<'tcx>, + pred: ty::Predicate<'tcx>, ) -> ty::Predicate<'tcx> { match pred.kind() { &ty::PredicateKind::Trait(ref data, constness) => { @@ -66,7 +66,7 @@ impl PredicateSet<'tcx> { Self { tcx, set: Default::default() } } - fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { + fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool { // We have to be careful here because we want // // for<'a> Foo<&'a int> @@ -81,10 +81,10 @@ impl PredicateSet<'tcx> { } } -impl>> Extend for PredicateSet<'tcx> { - fn extend>(&mut self, iter: I) { +impl Extend> for PredicateSet<'tcx> { + fn extend>>(&mut self, iter: I) { for pred in iter { - self.insert(pred.as_ref()); + self.insert(pred); } } } @@ -132,7 +132,7 @@ pub fn elaborate_obligations<'tcx>( mut obligations: Vec>, ) -> Elaborator<'tcx> { let mut visited = PredicateSet::new(tcx); - obligations.retain(|obligation| visited.insert(&obligation.predicate)); + obligations.retain(|obligation| visited.insert(obligation.predicate)); Elaborator { stack: obligations, visited } } @@ -172,7 +172,7 @@ impl Elaborator<'tcx> { // cases. One common case is when people define // `trait Sized: Sized { }` rather than `trait Sized { }`. let visited = &mut self.visited; - let obligations = obligations.filter(|o| visited.insert(&o.predicate)); + let obligations = obligations.filter(|o| visited.insert(o.predicate)); self.stack.extend(obligations); } @@ -260,7 +260,7 @@ impl Elaborator<'tcx> { } }) .map(|predicate_kind| predicate_kind.to_predicate(tcx)) - .filter(|predicate| visited.insert(predicate)) + .filter(|&predicate| visited.insert(predicate)) .map(|predicate| predicate_obligation(predicate, None)), ); } diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 9e8456689094f..877784bc50666 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1094,12 +1094,6 @@ pub struct CratePredicatesMap<'tcx> { pub predicates: FxHashMap, Span)]>, } -impl<'tcx> AsRef> for Predicate<'tcx> { - fn as_ref(&self) -> &Predicate<'tcx> { - self - } -} - impl<'tcx> Predicate<'tcx> { /// Performs a substitution suitable for going from a /// poly-trait-ref to supertraits that must hold if that @@ -1214,17 +1208,17 @@ pub struct TraitPredicate<'tcx> { pub type PolyTraitPredicate<'tcx> = ty::Binder>; impl<'tcx> TraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { + pub fn def_id(self) -> DefId { self.trait_ref.def_id } - pub fn self_ty(&self) -> Ty<'tcx> { + pub fn self_ty(self) -> Ty<'tcx> { self.trait_ref.self_ty() } } impl<'tcx> PolyTraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { + pub fn def_id(self) -> DefId { // Ok to skip binder since trait `DefId` does not care about regions. self.skip_binder().def_id() } diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index 716cbce60dcc9..0d986e60ff488 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -768,12 +768,12 @@ impl AutoTraitFinder<'tcx> { } } } - ty::PredicateKind::RegionOutlives(ref binder) => { + &ty::PredicateKind::RegionOutlives(binder) => { if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { return false; } } - ty::PredicateKind::TypeOutlives(ref binder) => { + &ty::PredicateKind::TypeOutlives(binder) => { match ( binder.no_bound_vars(), binder.map_bound_ref(|pred| pred.0).no_bound_vars(), diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 2aef8aaf0e303..8d514b94c0fe8 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -146,9 +146,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { continue; } - if self.error_implies(&error2.predicate, &error.predicate) + if self.error_implies(error2.predicate, error.predicate) && !(error2.index >= error.index - && self.error_implies(&error.predicate, &error2.predicate)) + && self.error_implies(error.predicate, error2.predicate)) { info!("skipping {:?} (implied by {:?})", error, error2); is_suppressed[index] = true; @@ -500,7 +500,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::PredicateKind::RegionOutlives(ref predicate) => { let predicate = self.resolve_vars_if_possible(predicate); let err = self - .region_outlives_predicate(&obligation.cause, &predicate) + .region_outlives_predicate(&obligation.cause, predicate) .err() .unwrap(); struct_span_err!( @@ -955,7 +955,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait InferCtxtPrivExt<'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. - fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool; + fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool; fn report_fulfillment_error( &self, @@ -1042,7 +1042,7 @@ trait InferCtxtPrivExt<'tcx> { impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. - fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool { + fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { if cond == error { return true; } @@ -1055,7 +1055,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } }; - for obligation in super::elaborate_predicates(self.tcx, std::iter::once(*cond)) { + for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) { if let ty::PredicateKind::Trait(implication, _) = obligation.predicate.kind() { let error = error.to_poly_trait_ref(); let implication = implication.to_poly_trait_ref(); diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index e44163f7bb1a4..896c4ead2df36 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -378,7 +378,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::RegionOutlives(ref binder) => { + &ty::PredicateKind::RegionOutlives(binder) => { match infcx.region_outlives_predicate(&obligation.cause, binder) { Ok(()) => ProcessResult::Changed(vec![]), Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), @@ -481,7 +481,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - ty::PredicateKind::Subtype(subtype) => { + &ty::PredicateKind::Subtype(subtype) => { match self.selcx.infcx().subtype_predicate( &obligation.cause, obligation.param_env, diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 914485fd408fc..72f089ae2a74a 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -1541,14 +1541,14 @@ fn assoc_ty_def( crate trait ProjectionCacheKeyExt<'tcx>: Sized { fn from_poly_projection_predicate( selcx: &mut SelectionContext<'cx, 'tcx>, - predicate: &ty::PolyProjectionPredicate<'tcx>, + predicate: ty::PolyProjectionPredicate<'tcx>, ) -> Option; } impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> { fn from_poly_projection_predicate( selcx: &mut SelectionContext<'cx, 'tcx>, - predicate: &ty::PolyProjectionPredicate<'tcx>, + predicate: ty::PolyProjectionPredicate<'tcx>, ) -> Option { let infcx = selcx.infcx(); // We don't do cross-snapshot caching of obligations with escaping regions, diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index b402aba65cdb7..05402fe3c194d 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -415,13 +415,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.predicate.kind() { - ty::PredicateKind::Trait(t, _) => { + &ty::PredicateKind::Trait(t, _) => { debug_assert!(!t.has_escaping_bound_vars()); - let obligation = obligation.with(*t); + let obligation = obligation.with(t); self.evaluate_trait_predicate_recursively(previous_stack, obligation) } - ty::PredicateKind::Subtype(p) => { + &ty::PredicateKind::Subtype(p) => { // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { mut obligations, .. })) => { @@ -463,8 +463,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::Projection(data) => { - let project_obligation = obligation.with(*data); + &ty::PredicateKind::Projection(data) => { + let project_obligation = obligation.with(data); match project::poly_project_and_unify_type(self, &project_obligation) { Ok(Some(mut subobligations)) => { self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); @@ -962,7 +962,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); if let Some(c) = - self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred) + self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred) { debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); return c; @@ -1247,7 +1247,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn check_candidate_cache( &mut self, param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>, + cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option>> { let tcx = self.tcx(); let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref; diff --git a/src/librustc_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs index f2d3f0e1116e2..f6f0c62c120f1 100644 --- a/src/librustc_trait_selection/traits/util.rs +++ b/src/librustc_trait_selection/traits/util.rs @@ -108,9 +108,9 @@ impl<'tcx> TraitAliasExpander<'tcx> { } // Don't recurse if this trait alias is already on the stack for the DFS search. - let anon_pred = anonymize_predicate(tcx, &pred); + let anon_pred = anonymize_predicate(tcx, pred); if item.path.iter().rev().skip(1).any(|(tr, _)| { - anonymize_predicate(tcx, &tr.without_const().to_predicate(tcx)) == anon_pred + anonymize_predicate(tcx, tr.without_const().to_predicate(tcx)) == anon_pred }) { return false; } diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 5118859765ed7..714ca7a30cff6 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -66,7 +66,7 @@ pub fn predicate_obligations<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, - predicate: &ty::Predicate<'tcx>, + predicate: ty::Predicate<'tcx>, span: Span, ) -> Vec> { let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index f393121a0adb8..e0a02ff8462a6 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -179,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); - self.deduce_sig_from_projection(None, &pb) + self.deduce_sig_from_projection(None, pb) }); let kind = object_type .principal_def_id() @@ -206,8 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligation.predicate ); - if let ty::PredicateKind::Projection(ref proj_predicate) = - obligation.predicate.kind() + if let &ty::PredicateKind::Projection(proj_predicate) = obligation.predicate.kind() { // Given a Projection predicate, we can potentially infer // the complete signature. @@ -238,7 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn deduce_sig_from_projection( &self, cause_span: Option, - projection: &ty::PolyProjectionPredicate<'tcx>, + projection: ty::PolyProjectionPredicate<'tcx>, ) -> Option> { let tcx = self.tcx; @@ -644,7 +643,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // where R is the return type we are expecting. This type `T` // will be our output. let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| { - if let ty::PredicateKind::Projection(ref proj_predicate) = obligation.predicate.kind() { + if let &ty::PredicateKind::Projection(proj_predicate) = obligation.predicate.kind() { self.deduce_future_output_from_projection(obligation.cause.span, proj_predicate) } else { None @@ -665,7 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn deduce_future_output_from_projection( &self, cause_span: Span, - predicate: &ty::PolyProjectionPredicate<'tcx>, + predicate: ty::PolyProjectionPredicate<'tcx>, ) -> Option> { debug!("deduce_future_output_from_projection(predicate={:?})", predicate); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 594cdab852fda..8c658923f0c51 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -205,7 +205,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // just to look for all the predicates directly. assert_eq!(dtor_predicates.parent, None); - for (predicate, predicate_sp) in dtor_predicates.predicates { + for &(predicate, predicate_sp) in dtor_predicates.predicates { // (We do not need to worry about deep analysis of type // expressions etc because the Drop impls are already forced // to take on a structure that is roughly an alpha-renaming of @@ -228,7 +228,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // This implementation solves (Issue #59497) and (Issue #58311). // It is unclear to me at the moment whether the approach based on `relate` // could be extended easily also to the other `Predicate`. - let predicate_matches_closure = |p: &'_ Predicate<'tcx>| { + let predicate_matches_closure = |p: Predicate<'tcx>| { let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); match (predicate.kind(), p.kind()) { (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => { @@ -241,12 +241,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( } }; - if !assumptions_in_impl_context.iter().any(predicate_matches_closure) { + if !assumptions_in_impl_context.iter().copied().any(predicate_matches_closure) { let item_span = tcx.hir().span(self_type_hir_id); let self_descr = tcx.def_kind(self_type_did).descr(self_type_did.to_def_id()); struct_span_err!( tcx.sess, - *predicate_sp, + predicate_sp, E0367, "`Drop` impl requires `{}` but the {} it is implemented for does not", predicate, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d5db613d9dcad..06e2d99983b0d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -819,8 +819,8 @@ fn check_where_clauses<'tcx, 'fcx>( debug!("check_where_clauses: predicates={:?}", predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = - predicates.predicates.iter().zip(predicates.spans.iter()).flat_map(|(p, sp)| { - traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, *sp) + predicates.predicates.iter().zip(predicates.spans.iter()).flat_map(|(&p, &sp)| { + traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, sp) }); for obligation in wf_obligations.chain(default_obligations) { diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index d30dc1b7a475e..b262ccf913a68 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -329,16 +329,13 @@ fn check_predicates<'tcx>( // which is sound because we forbid impls like the following // // impl AlwaysApplicable for D { } - let always_applicable_traits = impl1_predicates - .predicates - .iter() - .filter(|predicate| { + let always_applicable_traits = + impl1_predicates.predicates.iter().copied().filter(|&predicate| { matches!( trait_predicate_kind(tcx, predicate), Some(TraitSpecializationKind::AlwaysApplicable) ) - }) - .copied(); + }); // Include the well-formed predicates of the type parameters of the impl. for ty in tcx.impl_trait_ref(impl1_def_id).unwrap().substs.types() { @@ -361,12 +358,12 @@ fn check_predicates<'tcx>( for predicate in impl1_predicates.predicates { if !impl2_predicates.predicates.contains(&predicate) { - check_specialization_on(tcx, &predicate, span) + check_specialization_on(tcx, predicate, span) } } } -fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: &ty::Predicate<'tcx>, span: Span) { +fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) { debug!("can_specialize_on(predicate = {:?})", predicate); match predicate.kind() { // Global predicates are either always true or always false, so we @@ -399,7 +396,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: &ty::Predicate<'t fn trait_predicate_kind<'tcx>( tcx: TyCtxt<'tcx>, - predicate: &ty::Predicate<'tcx>, + predicate: ty::Predicate<'tcx>, ) -> Option { match predicate.kind() { ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => { From da57cedd215564385b1c0ea09d553121fe09c32e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 11:49:24 +0200 Subject: [PATCH 191/695] iterate List by value --- .../debuginfo/type_names.rs | 2 +- src/librustc_infer/infer/canonical/mod.rs | 2 +- .../infer/canonical/query_response.rs | 4 ++-- src/librustc_infer/infer/outlives/verify.rs | 5 ++--- src/librustc_middle/mir/mod.rs | 4 ++-- src/librustc_middle/ty/flags.rs | 2 +- src/librustc_middle/ty/list.rs | 22 +++++++++++++++---- src/librustc_middle/ty/outlives.rs | 2 +- src/librustc_middle/ty/print/obsolete.rs | 2 +- src/librustc_middle/ty/print/pretty.rs | 6 ++--- src/librustc_middle/ty/relate.rs | 6 ++--- src/librustc_middle/ty/structural_impls.rs | 2 +- src/librustc_middle/ty/sty.rs | 6 ++--- src/librustc_middle/ty/subst.rs | 4 ++-- src/librustc_middle/ty/util.rs | 4 ++-- src/librustc_middle/ty/walk.rs | 12 +++++----- src/librustc_mir/borrow_check/place_ext.rs | 2 +- .../borrow_check/places_conflict.rs | 14 ++++++------ .../borrow_check/type_check/mod.rs | 2 +- .../dataflow/move_paths/builder.rs | 2 +- src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/place.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 2 +- src/librustc_mir/transform/generator.rs | 4 ++-- src/librustc_mir_build/build/matches/mod.rs | 2 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_symbol_mangling/v0.rs | 2 +- src/librustc_trait_selection/opaque_types.rs | 6 ++--- .../traits/auto_trait.rs | 5 ++--- .../traits/chalk_fulfill.rs | 2 +- src/librustc_trait_selection/traits/mod.rs | 2 +- .../traits/object_safety.rs | 1 - .../traits/project.rs | 2 +- src/librustc_trait_selection/traits/select.rs | 2 +- src/librustc_ty/needs_drop.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 2 +- .../impl_wf_check/min_specialization.rs | 2 +- src/librustc_typeck/variance/constraints.rs | 2 +- .../src/needless_pass_by_value.rs | 3 +-- 40 files changed, 82 insertions(+), 72 deletions(-) diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs index 1d8730db54602..57a3d8b5edcaf 100644 --- a/src/librustc_codegen_ssa/debuginfo/type_names.rs +++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs @@ -48,7 +48,7 @@ pub fn push_debuginfo_type_name<'tcx>( } ty::Tuple(component_types) => { output.push('('); - for &component_type in component_types { + for component_type in component_types { push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited); output.push_str(", "); } diff --git a/src/librustc_infer/infer/canonical/mod.rs b/src/librustc_infer/infer/canonical/mod.rs index 7f58b29a73f36..7310d2c3bdcf8 100644 --- a/src/librustc_infer/infer/canonical/mod.rs +++ b/src/librustc_infer/infer/canonical/mod.rs @@ -87,7 +87,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) -> CanonicalVarValues<'tcx> { let var_values: IndexVec> = variables .iter() - .map(|info| self.instantiate_canonical_var(span, *info, &universe_map)) + .map(|info| self.instantiate_canonical_var(span, info, &universe_map)) .collect(); CanonicalVarValues { var_values } diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index 23c9eeb21bb8d..ab2393918c354 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -464,12 +464,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { if info.is_existential() { match opt_values[BoundVar::new(index)] { Some(k) => k, - None => self.instantiate_canonical_var(cause.span, *info, |u| { + None => self.instantiate_canonical_var(cause.span, info, |u| { universe_map[u.as_usize()] }), } } else { - self.instantiate_canonical_var(cause.span, *info, |u| { + self.instantiate_canonical_var(cause.span, info, |u| { universe_map[u.as_usize()] }) } diff --git a/src/librustc_infer/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs index cac1d2f050efc..82d32b008088d 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -50,7 +50,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // for further background and discussion. let mut bounds = substs .iter() - .filter_map(|&child| match child.unpack() { + .filter_map(|child| match child.unpack() { GenericArgKind::Type(ty) => Some(self.type_bound(ty)), GenericArgKind::Lifetime(_) => None, GenericArgKind::Const(_) => Some(self.recursive_bound(child)), @@ -223,8 +223,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // like `T` and `T::Item`. It may not work as well for things // like `>::Item`. let c_b = self.param_env.caller_bounds; - let param_bounds = - self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter().copied()); + let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter()); // Next, collect regions we scraped from the well-formedness // constraints in the fn signature. To do that, we walk the list diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 8247338ae0fad..ebdf738b417ff 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -2077,10 +2077,10 @@ impl Debug for Place<'_> { ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => { write!(fmt, "[-{:?} of {:?}]", offset, min_length)?; } - ProjectionElem::Subslice { from, to, from_end: true } if *to == 0 => { + ProjectionElem::Subslice { from, to, from_end: true } if to == 0 => { write!(fmt, "[{:?}:]", from)?; } - ProjectionElem::Subslice { from, to, from_end: true } if *from == 0 => { + ProjectionElem::Subslice { from, to, from_end: true } if from == 0 => { write!(fmt, "[:-{:?}]", to)?; } ProjectionElem::Subslice { from, to, from_end: true } => { diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index 042ffc4d1e550..edcb69c5e8cbd 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -129,7 +129,7 @@ impl FlagComputation { &ty::Dynamic(ref obj, r) => { let mut computation = FlagComputation::new(); for predicate in obj.skip_binder().iter() { - match *predicate { + match predicate { ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), ty::ExistentialPredicate::Projection(p) => { let mut proj_computation = FlagComputation::new(); diff --git a/src/librustc_middle/ty/list.rs b/src/librustc_middle/ty/list.rs index 6427c547a8f29..161783bb370d4 100644 --- a/src/librustc_middle/ty/list.rs +++ b/src/librustc_middle/ty/list.rs @@ -5,6 +5,7 @@ use rustc_serialize::{Encodable, Encoder}; use std::cmp::{self, Ordering}; use std::fmt; use std::hash::{Hash, Hasher}; +use std::iter; use std::mem; use std::ops::Deref; use std::ptr; @@ -21,6 +22,10 @@ extern "C" { /// the same contents can exist in the same context. /// This means we can use pointer for both /// equality comparisons and hashing. +/// +/// Unlike slices, The types contained in `List` are expected to be `Copy` +/// and iterating over a `List` returns `T` instead of a reference. +/// /// Note: `Slice` was already taken by the `Ty`. #[repr(C)] pub struct List { @@ -61,6 +66,15 @@ impl List { result } } + + // If this method didn't exist, we would use `slice.iter` due to + // deref coercion. + // + // This would be weird, as `self.into_iter` iterates over `T` directly. + #[inline(always)] + pub fn iter(&self) -> <&'_ List as IntoIterator>::IntoIter { + self.into_iter() + } } impl fmt::Debug for List { @@ -128,12 +142,12 @@ impl AsRef<[T]> for List { } } -impl<'a, T> IntoIterator for &'a List { - type Item = &'a T; - type IntoIter = <&'a [T] as IntoIterator>::IntoIter; +impl<'a, T: Copy> IntoIterator for &'a List { + type Item = T; + type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>; #[inline(always)] fn into_iter(self) -> Self::IntoIter { - self[..].iter() + self[..].iter().copied() } } diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs index 3e6a12df6887d..1da042e161737 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/src/librustc_middle/ty/outlives.rs @@ -70,7 +70,7 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo // consistent with previous (accidental) behavior. // See https://github.com/rust-lang/rust/issues/70917 // for further background and discussion. - for &child in substs { + for child in substs { match child.unpack() { GenericArgKind::Type(ty) => { compute_components(tcx, ty, out); diff --git a/src/librustc_middle/ty/print/obsolete.rs b/src/librustc_middle/ty/print/obsolete.rs index 41a6cd5466f5e..7d9943ab07902 100644 --- a/src/librustc_middle/ty/print/obsolete.rs +++ b/src/librustc_middle/ty/print/obsolete.rs @@ -47,7 +47,7 @@ impl DefPathBasedNames<'tcx> { } ty::Tuple(component_types) => { output.push('('); - for &component_type in component_types { + for component_type in component_types { self.push_type_name(component_type.expect_ty(), output, debug); output.push_str(", "); } diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index f4b795e548867..e5eb6ce3fb41c 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -495,7 +495,7 @@ pub trait PrettyPrinter<'tcx>: } ty::Never => p!(write("!")), ty::Tuple(ref tys) => { - p!(write("("), comma_sep(tys.iter().copied())); + p!(write("("), comma_sep(tys.iter())); if tys.len() == 1 { p!(write(",")); } @@ -560,7 +560,7 @@ pub trait PrettyPrinter<'tcx>: // FIXME(eddyb) print this with `print_def_path`. if !substs.is_empty() { p!(write("::")); - p!(generic_delimiters(|cx| cx.comma_sep(substs.iter().copied()))); + p!(generic_delimiters(|cx| cx.comma_sep(substs.iter()))); } return Ok(self); } @@ -1935,7 +1935,7 @@ define_print_and_forward_display! { (self, cx): &'tcx ty::List> { - p!(write("{{"), comma_sep(self.iter().copied()), write("}}")) + p!(write("{{"), comma_sep(self.iter()), write("}}")) } ty::TypeAndMut<'tcx> { diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index 594ffbcd83613..d507fcbc19404 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -143,7 +143,7 @@ pub fn relate_substs>( let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| { let variance = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(variance, a, b) + relation.relate_with_variance(variance, &a, &b) }); Ok(tcx.mk_substs(params)?) @@ -319,7 +319,7 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { ) -> RelateResult<'tcx, GeneratorWitness<'tcx>> { assert_eq!(a.0.len(), b.0.len()); let tcx = relation.tcx(); - let types = tcx.mk_type_list(a.0.iter().zip(b.0).map(|(a, b)| relation.relate(a, b)))?; + let types = tcx.mk_type_list(a.0.iter().zip(b.0).map(|(a, b)| relation.relate(&a, &b)))?; Ok(GeneratorWitness(types)) } } @@ -633,7 +633,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { let tcx = relation.tcx(); let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| { use crate::ty::ExistentialPredicate::*; - match (*ep_a, *ep_b) { + match (ep_a, ep_b) { (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)), (Projection(ref a), Projection(ref b)) => Ok(Projection(relation.relate(a, b)?)), (AutoTrait(ref a), AutoTrait(ref b)) if a == b => Ok(AutoTrait(*a)), diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index babe0c54801e8..5cf41982ff214 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -1093,7 +1093,7 @@ where // Look for the first element that changed if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| { let new_t = t.fold_with(folder); - if new_t == *t { None } else { Some((i, new_t)) } + if new_t == t { None } else { Some((i, new_t)) } }) { // An element changed, prepare to intern the resulting list let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len()); diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 0c9eef8093f33..8b87a63343c15 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -670,7 +670,7 @@ impl<'tcx> List> { pub fn projection_bounds<'a>( &'a self, ) -> impl Iterator> + 'a { - self.iter().filter_map(|predicate| match *predicate { + self.iter().filter_map(|predicate| match predicate { ExistentialPredicate::Projection(projection) => Some(projection), _ => None, }) @@ -678,7 +678,7 @@ impl<'tcx> List> { #[inline] pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { - self.iter().filter_map(|predicate| match *predicate { + self.iter().filter_map(|predicate| match predicate { ExistentialPredicate::AutoTrait(did) => Some(did), _ => None, }) @@ -709,7 +709,7 @@ impl<'tcx> Binder<&'tcx List>> { pub fn iter<'a>( &'a self, ) -> impl DoubleEndedIterator>> + 'tcx { - self.skip_binder().iter().cloned().map(Binder::bind) + self.skip_binder().iter().map(Binder::bind) } } diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs index 4d73f8f91ad2e..1529f1173b391 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/src/librustc_middle/ty/subst.rs @@ -340,11 +340,11 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { target_substs: SubstsRef<'tcx>, ) -> SubstsRef<'tcx> { let defs = tcx.generics_of(source_ancestor); - tcx.mk_substs(target_substs.iter().chain(&self[defs.params.len()..]).cloned()) + tcx.mk_substs(target_substs.iter().chain(self.iter().skip(defs.params.len()))) } pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> { - tcx.mk_substs(self.iter().take(generics.count()).cloned()) + tcx.mk_substs(self.iter().take(generics.count())) } } diff --git a/src/librustc_middle/ty/util.rs b/src/librustc_middle/ty/util.rs index f9c10488ffbc0..c2b794ca4bdd9 100644 --- a/src/librustc_middle/ty/util.rs +++ b/src/librustc_middle/ty/util.rs @@ -413,7 +413,7 @@ impl<'tcx> TyCtxt<'tcx> { let result = item_substs .iter() .zip(impl_substs.iter()) - .filter(|&(_, &k)| { + .filter(|&(_, k)| { match k.unpack() { GenericArgKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => { !impl_generics.region_param(ebr, self).pure_wrt_drop @@ -433,7 +433,7 @@ impl<'tcx> TyCtxt<'tcx> { } } }) - .map(|(&item_param, _)| item_param) + .map(|(item_param, _)| item_param) .collect(); debug!("destructor_constraint({:?}) = {:?}", def.did, result); result diff --git a/src/librustc_middle/ty/walk.rs b/src/librustc_middle/ty/walk.rs index 0093c60d7689b..bf988a4302633 100644 --- a/src/librustc_middle/ty/walk.rs +++ b/src/librustc_middle/ty/walk.rs @@ -128,7 +128,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) stack.push(lt.into()); } ty::Projection(data) => { - stack.extend(data.substs.iter().copied().rev()); + stack.extend(data.substs.iter().rev()); } ty::Dynamic(obj, lt) => { stack.push(lt.into()); @@ -143,7 +143,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } }; - substs.iter().copied().rev().chain(opt_ty.map(|ty| ty.into())) + substs.iter().rev().chain(opt_ty.map(|ty| ty.into())) })); } ty::Adt(_, substs) @@ -152,14 +152,14 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::Generator(_, substs, _) | ty::Tuple(substs) | ty::FnDef(_, substs) => { - stack.extend(substs.iter().copied().rev()); + stack.extend(substs.iter().rev()); } ty::GeneratorWitness(ts) => { - stack.extend(ts.skip_binder().iter().cloned().rev().map(|ty| ty.into())); + stack.extend(ts.skip_binder().iter().rev().map(|ty| ty.into())); } ty::FnPtr(sig) => { stack.push(sig.skip_binder().output().into()); - stack.extend(sig.skip_binder().inputs().iter().cloned().rev().map(|ty| ty.into())); + stack.extend(sig.skip_binder().inputs().iter().copied().rev().map(|ty| ty.into())); } }, GenericArgKind::Lifetime(_) => {} @@ -174,7 +174,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::ConstKind::Error => {} ty::ConstKind::Unevaluated(_, substs, _) => { - stack.extend(substs.iter().copied().rev()); + stack.extend(substs.iter().rev()); } } } diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index e53f50326d3d2..cadf1ebf1b774 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -47,7 +47,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { for (i, elem) in self.projection.iter().enumerate() { let proj_base = &self.projection[..i]; - if *elem == ProjectionElem::Deref { + if elem == ProjectionElem::Deref { let ty = Place::ty_from(self.local, proj_base, body, tcx).ty; match ty.kind { ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 45f77af4aba40..809b749f1e71f 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -163,8 +163,8 @@ fn place_components_conflict<'tcx>( body, borrow_local, borrow_proj_base, - borrow_c, - access_c, + &borrow_c, + &access_c, bias, ) { Overlap::Arbitrary => { @@ -420,24 +420,24 @@ fn place_projection_conflict<'tcx>( } } ( - ProjectionElem::ConstantIndex { + &ProjectionElem::ConstantIndex { offset: offset_from_begin, min_length: min_length1, from_end: false, }, - ProjectionElem::ConstantIndex { + &ProjectionElem::ConstantIndex { offset: offset_from_end, min_length: min_length2, from_end: true, }, ) | ( - ProjectionElem::ConstantIndex { + &ProjectionElem::ConstantIndex { offset: offset_from_end, min_length: min_length1, from_end: true, }, - ProjectionElem::ConstantIndex { + &ProjectionElem::ConstantIndex { offset: offset_from_begin, min_length: min_length2, from_end: false, @@ -449,7 +449,7 @@ fn place_projection_conflict<'tcx>( // element (like -1 in Python) and `min_length` the first. // Therefore, `min_length - offset_from_end` gives the minimal possible // offset from the beginning - if *offset_from_begin >= *min_length - *offset_from_end { + if offset_from_begin >= min_length - offset_from_end { debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE"); Overlap::EqualOrDisjoint } else { diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index bdbce1de745ad..1a64dcbf439d9 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -497,7 +497,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { return PlaceTy::from_ty(self.tcx().types.err); } } - place_ty = self.sanitize_projection(place_ty, elem, place, location) + place_ty = self.sanitize_projection(place_ty, &elem, place, location) } if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 0f2760b3f3b4e..b89884a4492f8 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -158,7 +158,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { }; if union_path.is_none() { - base = self.add_move_path(base, elem, |tcx| Place { + base = self.add_move_path(base, &elem, |tcx| Place { local: place.local, projection: tcx.intern_place_elems(&place.projection[..i + 1]), }); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index a3caa2048a1e7..8edfbbb3c22cb 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -466,7 +466,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let op = place .projection .iter() - .try_fold(base_op, |op, elem| self.operand_projection(op, elem))?; + .try_fold(base_op, |op, elem| self.operand_projection(op, &elem))?; trace!("eval_place_to_op: got {:?}", *op); Ok(op) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 6dadb8e4c67f4..4943e148731ed 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -634,7 +634,7 @@ where }; for elem in place.projection.iter() { - place_ty = self.place_projection(place_ty, elem)? + place_ty = self.place_projection(place_ty, &elem)? } self.dump_place(place_ty.place); diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 081f6435d9db9..c75e8414e8cca 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -449,7 +449,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { let type_length = instance .substs .iter() - .flat_map(|&arg| arg.walk()) + .flat_map(|arg| arg.walk()) .filter(|arg| match arg.unpack() { GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, GenericArgKind::Lifetime(_) => false, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 5f8104e7934eb..846ae55dffeff 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -132,7 +132,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { for elem in place.projection.iter() { if let PlaceElem::Index(local) = elem { - assert_ne!(*local, SELF_ARG); + assert_ne!(local, SELF_ARG); } } } @@ -171,7 +171,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { for elem in place.projection.iter() { if let PlaceElem::Index(local) = elem { - assert_ne!(*local, SELF_ARG); + assert_ne!(local, SELF_ARG); } } } diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index 1071a4c97df65..147c09d8f3af6 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -1042,7 +1042,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { matched_candidates.iter().flat_map(|candidate| &candidate.bindings) { if let Some(i) = - source.projection.iter().rposition(|elem| *elem == ProjectionElem::Deref) + source.projection.iter().rposition(|elem| elem == ProjectionElem::Deref) { let proj_base = &source.projection[..i]; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 9a63e39f535c1..cb896810951ba 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -176,7 +176,7 @@ where // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. for predicate in *predicates.skip_binder() { - let trait_ref = match *predicate { + let trait_ref = match predicate { ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), ty::ExistentialPredicate::AutoTrait(def_id) => { diff --git a/src/librustc_symbol_mangling/v0.rs b/src/librustc_symbol_mangling/v0.rs index 3b439e09a9d15..1a536b6a4294f 100644 --- a/src/librustc_symbol_mangling/v0.rs +++ b/src/librustc_symbol_mangling/v0.rs @@ -477,7 +477,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { predicates: &'tcx ty::List>, ) -> Result { for predicate in predicates { - match *predicate { + match predicate { ty::ExistentialPredicate::Trait(trait_ref) => { // Use a type that can't appear in defaults of type parameters. let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0)); diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 2544e4ddea2ec..767640bcd3c30 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -647,7 +647,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // shifting. let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); let map: FxHashMap, GenericArg<'tcx>> = - substs.iter().enumerate().map(|(index, subst)| (*subst, id_substs[index])).collect(); + substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); // Convert the type from the function into a type valid outside // the function, by replacing invalid regions with 'static, @@ -891,7 +891,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { // during codegen. let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, &kind)| { + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { if index < generics.parent_count { // Accommodate missing regions in the parent kinds... self.fold_kind_mapping_missing_regions_to_empty(kind) @@ -906,7 +906,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { ty::Generator(def_id, substs, movability) => { let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, &kind)| { + let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { if index < generics.parent_count { // Accommodate missing regions in the parent kinds... self.fold_kind_mapping_missing_regions_to_empty(kind) diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index 0d986e60ff488..433e1e46f6bba 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -281,9 +281,8 @@ impl AutoTraitFinder<'tcx> { }, })); - let computed_preds = param_env.caller_bounds.iter().cloned(); - let mut user_computed_preds: FxHashSet<_> = - user_env.caller_bounds.iter().cloned().collect(); + let computed_preds = param_env.caller_bounds.iter(); + let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds.iter().collect(); let mut new_env = param_env; let dummy_cause = ObligationCause::dummy(); diff --git a/src/librustc_trait_selection/traits/chalk_fulfill.rs b/src/librustc_trait_selection/traits/chalk_fulfill.rs index be0512dcac95b..2d4d582c939b6 100644 --- a/src/librustc_trait_selection/traits/chalk_fulfill.rs +++ b/src/librustc_trait_selection/traits/chalk_fulfill.rs @@ -87,7 +87,7 @@ fn environment<'tcx>( NodeKind::TraitImpl => { let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); - inputs.extend(trait_ref.substs.iter().flat_map(|&arg| arg.walk())); + inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk())); } // In an inherent impl, we assume that the receiver type and all its diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 3daa9109aafe8..a5b9fd8f8d8e1 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -302,7 +302,7 @@ pub fn normalize_param_env_or_error<'tcx>( ); let mut predicates: Vec<_> = - util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.into_iter().cloned()) + util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.into_iter()) .map(|obligation| obligation.predicate) .collect(); diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index b2d684e674f02..5befc797a517a 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -658,7 +658,6 @@ fn receiver_is_dispatchable<'tcx>( let caller_bounds: Vec> = param_env .caller_bounds .iter() - .cloned() .chain(iter::once(unsize_predicate)) .chain(iter::once(trait_predicate)) .collect(); diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 72f089ae2a74a..cd5d0be003aaf 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -872,7 +872,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>( obligation_trait_ref, candidate_set, ProjectionTyCandidate::ParamEnv, - obligation.param_env.caller_bounds.iter().cloned(), + obligation.param_env.caller_bounds.iter(), ); } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 05402fe3c194d..82a3873f406a8 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -3154,7 +3154,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Check that the source struct with the target's // unsizing parameters is equal to the target. - let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, &k)| { + let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, k)| { if unsizing_params.contains(i as u32) { substs_b[i] } else { k } })); let new_struct = tcx.mk_adt(def, substs); diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs index e94a47f079a63..1b059fa3dbdf0 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/src/librustc_ty/needs_drop.rs @@ -11,7 +11,7 @@ type NeedsDropResult = Result; fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { let adt_fields = - move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter().copied()); + move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); // If we don't know a type doesn't need drop, for example if it's a type // parameter without a `Copy` bound, then we conservatively return that it // needs drop. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c452859414cfb..0c8613d82db76 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2769,7 +2769,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { ty::GenericPredicates { parent: None, predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map( - |&predicate| match predicate.kind() { + |predicate| match predicate.kind() { ty::PredicateKind::Trait(ref data, _) if data.skip_binder().self_ty().is_param(index) => { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 06e2d99983b0d..e154184f1822c 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -900,7 +900,7 @@ fn check_opaque_types<'fcx, 'tcx>( if may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) { trace!("check_opaque_types: may define, generics={:#?}", generics); let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); - for (i, &arg) in substs.iter().enumerate() { + for (i, arg) in substs.iter().enumerate() { let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)), diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index b262ccf913a68..ded27605d1586 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -229,7 +229,7 @@ fn unconstrained_parent_impl_substs<'tcx>( .iter() .enumerate() .filter(|&(idx, _)| !constrained_params.contains(&(idx as u32))) - .map(|(_, arg)| *arg) + .map(|(_, arg)| arg) .collect() } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 3a680f55c8c30..e42cf3ef32a28 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Tuple(subtys) => { - for &subty in subtys { + for subty in subtys { self.add_constraints_from_ty(current, subty.expect_ty(), variance); } } diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 60c5360054334..1621c7f947c33 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let fn_def_id = cx.tcx.hir().local_def_id(hir_id); - let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter().copied()) + let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter()) .filter(|p| !p.is_global()) .filter_map(|obligation| { if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate.kind() { @@ -179,7 +179,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { .substs .iter() .skip(1) - .cloned() .collect::>(); implements_trait(cx, ty_empty_region, t.def_id(), ty_params) }) From 810dbf7770cfaa52ed5cdc2f833fa11e4034c029 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 12:02:54 +0200 Subject: [PATCH 192/695] take mir::PlaceElem by value --- src/librustc_codegen_ssa/mir/analyze.rs | 4 ++-- src/librustc_codegen_ssa/mir/place.rs | 14 +++++++------- src/librustc_middle/mir/tcx.rs | 6 +++--- src/librustc_middle/mir/visit.rs | 16 ++++++++-------- .../borrow_check/places_conflict.rs | 18 +++++++++--------- src/librustc_mir/borrow_check/renumber.rs | 8 ++++---- .../borrow_check/type_check/mod.rs | 6 +++--- src/librustc_mir/dataflow/drop_flag_effects.rs | 4 ++-- .../dataflow/move_paths/builder.rs | 6 +++--- src/librustc_mir/interpret/operand.rs | 6 +++--- src/librustc_mir/interpret/place.rs | 8 ++++---- .../transform/check_consts/qualifs.rs | 4 ++-- .../transform/check_consts/validation.rs | 2 +- src/librustc_mir/transform/elaborate_drops.rs | 10 +++++----- src/librustc_mir/transform/promote_consts.rs | 4 ++-- 15 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 5e3a37e20bd4f..fa0f29acc7433 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -104,7 +104,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { ) { let cx = self.fx.cx; - if let [proj_base @ .., elem] = place_ref.projection { + if let &[ref proj_base @ .., elem] = place_ref.projection { let mut base_context = if context.is_mutating_use() { PlaceContext::MutatingUse(MutatingUseContext::Projection) } else { @@ -186,7 +186,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { // now that we have moved to the "slice of projections" representation. if let mir::ProjectionElem::Index(local) = elem { self.visit_local( - local, + &local, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location, ); diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index aaba2ec1362ac..2be0679382900 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -429,7 +429,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_consume(bx, mir::PlaceRef { local, projection: proj_base }) .deref(bx.cx()) } - mir::PlaceRef { local, projection: [proj_base @ .., elem] } => { + mir::PlaceRef { local, projection: &[ref proj_base @ .., elem] } => { // FIXME turn this recursion into iteration let cg_base = self.codegen_place(bx, mir::PlaceRef { local, projection: proj_base }); @@ -440,7 +440,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cg_base.project_field(bx, field.index()) } mir::ProjectionElem::Index(index) => { - let index = &mir::Operand::Copy(mir::Place::from(*index)); + let index = &mir::Operand::Copy(mir::Place::from(index)); let index = self.codegen_operand(bx, index); let llindex = index.immediate(); cg_base.project_index(bx, llindex) @@ -450,7 +450,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { from_end: false, min_length: _, } => { - let lloffset = bx.cx().const_usize(*offset as u64); + let lloffset = bx.cx().const_usize(offset as u64); cg_base.project_index(bx, lloffset) } mir::ProjectionElem::ConstantIndex { @@ -458,14 +458,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { from_end: true, min_length: _, } => { - let lloffset = bx.cx().const_usize(*offset as u64); + let lloffset = bx.cx().const_usize(offset as u64); let lllen = cg_base.len(bx.cx()); let llindex = bx.sub(lllen, lloffset); cg_base.project_index(bx, llindex) } mir::ProjectionElem::Subslice { from, to, from_end } => { let mut subslice = - cg_base.project_index(bx, bx.cx().const_usize(*from as u64)); + cg_base.project_index(bx, bx.cx().const_usize(from as u64)); let projected_ty = PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem).ty; subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); @@ -474,7 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(from_end, "slice subslices should be `from_end`"); subslice.llextra = Some(bx.sub( cg_base.llextra.unwrap(), - bx.cx().const_usize((*from as u64) + (*to as u64)), + bx.cx().const_usize((from as u64) + (to as u64)), )); } @@ -487,7 +487,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { subslice } - mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, *v), + mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v), } } }; diff --git a/src/librustc_middle/mir/tcx.rs b/src/librustc_middle/mir/tcx.rs index 17edd9f4cb643..4747aec2d5c24 100644 --- a/src/librustc_middle/mir/tcx.rs +++ b/src/librustc_middle/mir/tcx.rs @@ -56,8 +56,8 @@ impl<'tcx> PlaceTy<'tcx> { /// Convenience wrapper around `projection_ty_core` for /// `PlaceElem`, where we can just use the `Ty` that is already /// stored inline on field projection elems. - pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, ty::ParamEnv::empty(), elem, |_, _, ty| ty) + pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { + self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty) } /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` @@ -124,7 +124,7 @@ impl<'tcx> Place<'tcx> { { projection .iter() - .fold(PlaceTy::from_ty(local_decls.local_decls()[local].ty), |place_ty, elem| { + .fold(PlaceTy::from_ty(local_decls.local_decls()[local].ty), |place_ty, &elem| { place_ty.projection_ty(tcx, elem) }) } diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs index 02164244771c9..a29b7b75294b7 100644 --- a/src/librustc_middle/mir/visit.rs +++ b/src/librustc_middle/mir/visit.rs @@ -903,7 +903,7 @@ macro_rules! visit_place_fns { let mut projection = Cow::Borrowed(projection); for i in 0..projection.len() { - if let Some(elem) = projection.get(i) { + if let Some(&elem) = projection.get(i) { if let Some(elem) = self.process_projection_elem(elem, location) { // This converts the borrowed projection into `Cow::Owned(_)` and returns a // clone of the projection so we can mutate and reintern later. @@ -921,19 +921,19 @@ macro_rules! visit_place_fns { fn process_projection_elem( &mut self, - elem: &PlaceElem<'tcx>, + elem: PlaceElem<'tcx>, location: Location, ) -> Option> { match elem { PlaceElem::Index(local) => { - let mut new_local = *local; + let mut new_local = local; self.visit_local( &mut new_local, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location, ); - if new_local == *local { None } else { Some(PlaceElem::Index(new_local)) } + if new_local == local { None } else { Some(PlaceElem::Index(new_local)) } } PlaceElem::Deref | PlaceElem::Field(..) @@ -959,7 +959,7 @@ macro_rules! visit_place_fns { &mut self, local: Local, proj_base: &[PlaceElem<'tcx>], - elem: &PlaceElem<'tcx>, + elem: PlaceElem<'tcx>, context: PlaceContext, location: Location, ) { @@ -990,7 +990,7 @@ macro_rules! visit_place_fns { location: Location, ) { let mut cursor = projection; - while let [proj_base @ .., elem] = cursor { + while let &[ref proj_base @ .., elem] = cursor { cursor = proj_base; self.visit_projection_elem(local, cursor, elem, context, location); } @@ -1000,7 +1000,7 @@ macro_rules! visit_place_fns { &mut self, _local: Local, _proj_base: &[PlaceElem<'tcx>], - elem: &PlaceElem<'tcx>, + elem: PlaceElem<'tcx>, _context: PlaceContext, location: Location, ) { @@ -1010,7 +1010,7 @@ macro_rules! visit_place_fns { } ProjectionElem::Index(local) => { self.visit_local( - local, + &local, PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy), location, ); diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 809b749f1e71f..246e4826e0e76 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -138,7 +138,7 @@ fn place_components_conflict<'tcx>( } // loop invariant: borrow_c is always either equal to access_c or disjoint from it. - for (i, (borrow_c, access_c)) in + for (i, (borrow_c, &access_c)) in borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate() { debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); @@ -163,8 +163,8 @@ fn place_components_conflict<'tcx>( body, borrow_local, borrow_proj_base, - &borrow_c, - &access_c, + borrow_c, + access_c, bias, ) { Overlap::Arbitrary => { @@ -313,8 +313,8 @@ fn place_projection_conflict<'tcx>( body: &Body<'tcx>, pi1_local: Local, pi1_proj_base: &[PlaceElem<'tcx>], - pi1_elem: &PlaceElem<'tcx>, - pi2_elem: &PlaceElem<'tcx>, + pi1_elem: PlaceElem<'tcx>, + pi2_elem: PlaceElem<'tcx>, bias: PlaceConflictBias, ) -> Overlap { match (pi1_elem, pi2_elem) { @@ -420,24 +420,24 @@ fn place_projection_conflict<'tcx>( } } ( - &ProjectionElem::ConstantIndex { + ProjectionElem::ConstantIndex { offset: offset_from_begin, min_length: min_length1, from_end: false, }, - &ProjectionElem::ConstantIndex { + ProjectionElem::ConstantIndex { offset: offset_from_end, min_length: min_length2, from_end: true, }, ) | ( - &ProjectionElem::ConstantIndex { + ProjectionElem::ConstantIndex { offset: offset_from_end, min_length: min_length1, from_end: true, }, - &ProjectionElem::ConstantIndex { + ProjectionElem::ConstantIndex { offset: offset_from_begin, min_length: min_length2, from_end: false, diff --git a/src/librustc_mir/borrow_check/renumber.rs b/src/librustc_mir/borrow_check/renumber.rs index 5956896881941..5df033b48c1f9 100644 --- a/src/librustc_mir/borrow_check/renumber.rs +++ b/src/librustc_mir/borrow_check/renumber.rs @@ -66,14 +66,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { fn process_projection_elem( &mut self, - elem: &PlaceElem<'tcx>, + elem: PlaceElem<'tcx>, _: Location, ) -> Option> { if let PlaceElem::Field(field, ty) = elem { - let new_ty = self.renumber_regions(ty); + let new_ty = self.renumber_regions(&ty); - if new_ty != *ty { - return Some(PlaceElem::Field(*field, new_ty)); + if new_ty != ty { + return Some(PlaceElem::Field(field, new_ty)); } } diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 1a64dcbf439d9..ac7da7ee42d66 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -497,7 +497,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { return PlaceTy::from_ty(self.tcx().types.err); } } - place_ty = self.sanitize_projection(place_ty, &elem, place, location) + place_ty = self.sanitize_projection(place_ty, elem, place, location) } if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { @@ -611,14 +611,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { fn sanitize_projection( &mut self, base: PlaceTy<'tcx>, - pi: &PlaceElem<'tcx>, + pi: PlaceElem<'tcx>, place: &Place<'tcx>, location: Location, ) -> PlaceTy<'tcx> { debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); let tcx = self.tcx(); let base_ty = base.ty; - match *pi { + match pi { ProjectionElem::Deref => { let deref_ty = base_ty.builtin_deref(true); PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| { diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index 91b342ae5c36a..6dd06743e2d5b 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -12,12 +12,12 @@ pub fn move_path_children_matching<'tcx, F>( mut cond: F, ) -> Option where - F: FnMut(&mir::PlaceElem<'tcx>) -> bool, + F: FnMut(mir::PlaceElem<'tcx>) -> bool, { let mut next_child = move_data.move_paths[path].first_child; while let Some(child_index) = next_child { let move_path_children = &move_data.move_paths[child_index]; - if let Some(elem) = move_path_children.place.projection.last() { + if let Some(&elem) = move_path_children.place.projection.last() { if cond(elem) { return Some(child_index); } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index b89884a4492f8..427ab1ca5cd22 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -158,7 +158,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { }; if union_path.is_none() { - base = self.add_move_path(base, &elem, |tcx| Place { + base = self.add_move_path(base, elem, |tcx| Place { local: place.local, projection: tcx.intern_place_elems(&place.projection[..i + 1]), }); @@ -176,7 +176,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn add_move_path( &mut self, base: MovePathIndex, - elem: &PlaceElem<'tcx>, + elem: PlaceElem<'tcx>, mk_place: impl FnOnce(TyCtxt<'tcx>) -> Place<'tcx>, ) -> MovePathIndex { let MoveDataBuilder { @@ -485,7 +485,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { let elem = ProjectionElem::ConstantIndex { offset, min_length: len, from_end: false }; let path = - self.add_move_path(base_path, &elem, |tcx| tcx.mk_place_elem(base_place, elem)); + self.add_move_path(base_path, elem, |tcx| tcx.mk_place_elem(base_place, elem)); self.record_move(place, path); } } else { diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 8edfbbb3c22cb..95bc9810dab80 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -400,10 +400,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn operand_projection( &self, base: OpTy<'tcx, M::PointerTag>, - proj_elem: &mir::PlaceElem<'tcx>, + proj_elem: mir::PlaceElem<'tcx>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc_middle::mir::ProjectionElem::*; - Ok(match *proj_elem { + Ok(match proj_elem { Field(field, _) => self.operand_field(base, field.index())?, Downcast(_, variant) => self.operand_downcast(base, variant)?, Deref => self.deref_operand(base)?.into(), @@ -466,7 +466,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let op = place .projection .iter() - .try_fold(base_op, |op, elem| self.operand_projection(op, &elem))?; + .try_fold(base_op, |op, elem| self.operand_projection(op, elem))?; trace!("eval_place_to_op: got {:?}", *op); Ok(op) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4943e148731ed..dc6967c2c49e5 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -517,10 +517,10 @@ where pub(super) fn mplace_projection( &self, base: MPlaceTy<'tcx, M::PointerTag>, - proj_elem: &mir::PlaceElem<'tcx>, + proj_elem: mir::PlaceElem<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { use rustc_middle::mir::ProjectionElem::*; - Ok(match *proj_elem { + Ok(match proj_elem { Field(field, _) => self.mplace_field(base, field.index())?, Downcast(_, variant) => self.mplace_downcast(base, variant)?, Deref => self.deref_operand(base.into())?, @@ -605,10 +605,10 @@ where pub fn place_projection( &mut self, base: PlaceTy<'tcx, M::PointerTag>, - proj_elem: &mir::ProjectionElem>, + &proj_elem: &mir::ProjectionElem>, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc_middle::mir::ProjectionElem::*; - Ok(match *proj_elem { + Ok(match proj_elem { Field(field, _) => self.place_field(base, field.index())?, Downcast(_, variant) => self.place_downcast(base, variant)?, Deref => self.deref_operand(self.place_to_op(base)?)?.into(), diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index fc6860b40e8d2..05a7c78d59d39 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -206,8 +206,8 @@ where F: FnMut(Local) -> bool, { let mut projection = place.projection; - while let [ref proj_base @ .., proj_elem] = projection { - match *proj_elem { + while let &[ref proj_base @ .., proj_elem] = projection { + match proj_elem { ProjectionElem::Index(index) if in_local(index) => return true, ProjectionElem::Deref diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 987c9e24fc3c3..80094e154bf66 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -432,7 +432,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { &mut self, place_local: Local, proj_base: &[PlaceElem<'tcx>], - elem: &PlaceElem<'tcx>, + elem: PlaceElem<'tcx>, context: PlaceContext, location: Location, ) { diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index e379e5ee656b7..e4129f447d532 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -213,7 +213,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { fn field_subpath(&self, path: Self::Path, field: Field) -> Option { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { - ProjectionElem::Field(idx, _) => *idx == field, + ProjectionElem::Field(idx, _) => idx == field, _ => false, }) } @@ -221,9 +221,9 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - debug_assert!(size == *min_length, "min_length should be exact for arrays"); + debug_assert!(size == min_length, "min_length should be exact for arrays"); assert!(!from_end, "from_end should not be used for array element ConstantIndex"); - *offset == index + offset == index } _ => false, }) @@ -231,13 +231,13 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { fn deref_subpath(&self, path: Self::Path) -> Option { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| { - *e == ProjectionElem::Deref + e == ProjectionElem::Deref }) } fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { - ProjectionElem::Downcast(_, idx) => *idx == variant, + ProjectionElem::Downcast(_, idx) => idx == variant, _ => false, }) } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 13a8b9a1000c9..6caa2b48f3d45 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -340,7 +340,7 @@ impl<'tcx> Validator<'_, 'tcx> { // `let _: &'static _ = &(Cell::new(1), 2).1;` let mut place_projection = &place.projection[..]; // FIXME(eddyb) use a forward loop instead of a reverse one. - while let [proj_base @ .., elem] = place_projection { + while let &[ref proj_base @ .., elem] = place_projection { // FIXME(eddyb) this is probably excessive, with // the exception of `union` member accesses. let ty = @@ -676,7 +676,7 @@ impl<'tcx> Validator<'_, 'tcx> { if has_mut_interior { let mut place_projection = place.projection; // FIXME(eddyb) use a forward loop instead of a reverse one. - while let [proj_base @ .., elem] = place_projection { + while let &[ref proj_base @ .., elem] = place_projection { // FIXME(eddyb) this is probably excessive, with // the exception of `union` member accesses. let ty = Place::ty_from(place.local, proj_base, self.body, self.tcx) From e820a03d1c905d58b27d7ac6d85f450f9754ba79 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 11:49:24 +0200 Subject: [PATCH 193/695] iterate List by value --- clippy_lints/src/needless_pass_by_value.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 60c5360054334..1621c7f947c33 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let fn_def_id = cx.tcx.hir().local_def_id(hir_id); - let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter().copied()) + let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.iter()) .filter(|p| !p.is_global()) .filter_map(|obligation| { if let ty::PredicateKind::Trait(poly_trait_ref, _) = obligation.predicate.kind() { @@ -179,7 +179,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { .substs .iter() .skip(1) - .cloned() .collect::>(); implements_trait(cx, ty_empty_region, t.def_id(), ty_params) }) From d01f1314b7f1f29fbb7352becad7caa821774227 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 23 May 2020 13:19:57 +0200 Subject: [PATCH 194/695] Improve E0601 explanation --- src/librustc_error_codes/error_codes/E0601.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0601.md b/src/librustc_error_codes/error_codes/E0601.md index 8180c5db46fba..7194b7971d38f 100644 --- a/src/librustc_error_codes/error_codes/E0601.md +++ b/src/librustc_error_codes/error_codes/E0601.md @@ -1,5 +1,6 @@ -No `main` function was found in a binary crate. To fix this error, add a -`main` function. For example: +No `main` function was found in a binary crate. + +To fix this error, add a `main` function: ``` fn main() { From 749d9e7a26a29b5689f2daaaa9b89f654b2862af Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sat, 23 May 2020 07:29:22 -0400 Subject: [PATCH 195/695] Correct small typo: 'not' -> 'note' --- src/libstd/f32.rs | 2 +- src/libstd/f64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8e743ace99bfb..deb9eb5b4b05c 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -882,7 +882,7 @@ impl f32 { /// Returns `max` if `self` is greater than `max`, and `min` if `self` is /// less than `min`. Otherwise this returns `self`. /// - /// Not that this function returns NaN if the initial value was NaN as + /// Note that this function returns NaN if the initial value was NaN as /// well. /// /// # Panics diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index fe64d27b1efc8..b79e550ed265e 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -884,7 +884,7 @@ impl f64 { /// Returns `max` if `self` is greater than `max`, and `min` if `self` is /// less than `min`. Otherwise this returns `self`. /// - /// Not that this function returns NaN if the initial value was NaN as + /// Note that this function returns NaN if the initial value was NaN as /// well. /// /// # Panics From 1c9b96b7540ed1f3df0c3559bde2d5ce1bea4ef3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 19:18:37 +0200 Subject: [PATCH 196/695] add warning sign to UB examples --- src/libcore/mem/maybe_uninit.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index f7ea7eba7b16b..01c97444ae3ae 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -20,9 +20,9 @@ use crate::mem::ManuallyDrop; /// # #![allow(invalid_value)] /// use std::mem::{self, MaybeUninit}; /// -/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! +/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! ⚠️ /// // The equivalent code with `MaybeUninit<&i32>`: -/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior! +/// let x: &i32 = unsafe { MaybeUninit::zeroed().assume_init() }; // undefined behavior! ⚠️ /// ``` /// /// This is exploited by the compiler for various optimizations, such as eliding @@ -35,9 +35,9 @@ use crate::mem::ManuallyDrop; /// # #![allow(invalid_value)] /// use std::mem::{self, MaybeUninit}; /// -/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! +/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! ⚠️ /// // The equivalent code with `MaybeUninit`: -/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! +/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️ /// ``` /// /// Moreover, uninitialized memory is special in that the compiler knows that @@ -49,9 +49,9 @@ use crate::mem::ManuallyDrop; /// # #![allow(invalid_value)] /// use std::mem::{self, MaybeUninit}; /// -/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! +/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! ⚠️ /// // The equivalent code with `MaybeUninit`: -/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! +/// let x: i32 = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️ /// ``` /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) @@ -348,7 +348,7 @@ impl MaybeUninit { /// let x = MaybeUninit::<(u8, NotZero)>::zeroed(); /// let x = unsafe { x.assume_init() }; /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant. - /// // This is undefined behavior. + /// // This is undefined behavior. ⚠️ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline] @@ -400,7 +400,7 @@ impl MaybeUninit { /// /// let x = MaybeUninit::>::uninit(); /// let x_vec = unsafe { &*x.as_ptr() }; - /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️ /// ``` /// /// (Notice that the rules around references to uninitialized data are not finalized yet, but @@ -437,7 +437,7 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::>::uninit(); /// let x_vec = unsafe { &mut *x.as_mut_ptr() }; - /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️ /// ``` /// /// (Notice that the rules around references to uninitialized data are not finalized yet, but @@ -489,7 +489,7 @@ impl MaybeUninit { /// /// let x = MaybeUninit::>::uninit(); /// let x_init = unsafe { x.assume_init() }; - /// // `x` had not been initialized yet, so this last line caused undefined behavior. + /// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️ /// ``` #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] @@ -553,7 +553,7 @@ impl MaybeUninit { /// x.write(Some(vec![0,1,2])); /// let x1 = unsafe { x.read() }; /// let x2 = unsafe { x.read() }; - /// // We now created two copies of the same vector, leading to a double-free when + /// // We now created two copies of the same vector, leading to a double-free ⚠️ when /// // they both get dropped! /// ``` #[unstable(feature = "maybe_uninit_extra", issue = "63567")] @@ -603,7 +603,7 @@ impl MaybeUninit { /// /// let x = MaybeUninit::>::uninit(); /// let x_vec: &Vec = unsafe { x.get_ref() }; - /// // We have created a reference to an uninitialized vector! This is undefined behavior. + /// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️ /// ``` /// /// ```rust,no_run @@ -686,7 +686,7 @@ impl MaybeUninit { /// unsafe { /// *b.get_mut() = true; /// // We have created a (mutable) reference to an uninitialized `bool`! - /// // This is undefined behavior. + /// // This is undefined behavior. ⚠️ /// } /// ``` /// From b7cfb6a9ac1b59f62cfce2be6d09e45557af84d5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 23 May 2020 13:11:28 +0100 Subject: [PATCH 197/695] Improve debugging --- src/librustc_mir_build/hair/pattern/_match.rs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 626e531c807b7..928d1f6a68abc 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -1066,10 +1066,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { constructor: &Constructor<'tcx>, ty: Ty<'tcx>, ) -> Self { - debug!("Fields::wildcards({:#?}, {:?})", constructor, ty); let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); - match constructor { + let ret = match constructor { Single | Variant(_) => match ty.kind { ty::Tuple(ref fs) => { Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty())) @@ -1129,7 +1128,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { _ => bug!("bad slice pattern {:?} {:?}", constructor, ty), }, ConstantValue(..) | FloatRange(..) | IntRange(..) | NonExhaustive => Fields::empty(), - } + }; + debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); + ret } fn len(&self) -> usize { @@ -1870,7 +1871,7 @@ crate fn is_useful<'p, 'tcx>( debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head()); - if let Some(constructor) = pat_constructor(cx.tcx, cx.param_env, v.head()) { + let ret = if let Some(constructor) = pat_constructor(cx.tcx, cx.param_env, v.head()) { debug!("is_useful - expanding constructor: {:#?}", constructor); split_grouped_constructors( cx.tcx, @@ -1901,11 +1902,11 @@ crate fn is_useful<'p, 'tcx>( let used_ctors: Vec> = matrix.heads().filter_map(|p| pat_constructor(cx.tcx, cx.param_env, p)).collect(); - debug!("used_ctors = {:#?}", used_ctors); + debug!("is_useful_used_ctors = {:#?}", used_ctors); // `all_ctors` are all the constructors for the given type, which // should all be represented (or caught with the wild pattern `_`). let all_ctors = all_constructors(cx, pcx); - debug!("all_ctors = {:#?}", all_ctors); + debug!("is_useful_all_ctors = {:#?}", all_ctors); // `missing_ctors` is the set of constructors from the same type as the // first column of `matrix` that are matched only by wildcard patterns @@ -1920,7 +1921,7 @@ crate fn is_useful<'p, 'tcx>( // can be big. let missing_ctors = MissingConstructors::new(all_ctors, used_ctors); - debug!("missing_ctors.empty()={:#?}", missing_ctors.is_empty(),); + debug!("is_useful_missing_ctors.empty()={:#?}", missing_ctors.is_empty(),); if missing_ctors.is_empty() { let (all_ctors, _) = missing_ctors.into_inner(); @@ -1988,7 +1989,9 @@ crate fn is_useful<'p, 'tcx>( usefulness.apply_missing_ctors(cx, pcx.ty, &missing_ctors) } } - } + }; + debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret); + ret } /// A shorthand for the `U(S(c, P), S(c, q))` operation from the paper. I.e., `is_useful` applied @@ -2647,7 +2650,10 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), }; - debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result); + debug!( + "specialize({:#?}, {:#?}, {:#?}) = {:#?}", + pat, constructor, ctor_wild_subpatterns, result + ); result } From a5734ca41748dfd62904c1b5a1ade7ecd0f9c11e Mon Sep 17 00:00:00 2001 From: mendess Date: Sat, 23 May 2020 14:08:53 +0100 Subject: [PATCH 198/695] Override Box::<[T]>::clone_from --- src/liballoc/boxed.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8ef6090c743a9..bbe68e4222a1f 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -1090,6 +1090,14 @@ impl Clone for Box<[T]> { fn clone(&self) -> Self { self.to_vec().into_boxed_slice() } + + fn clone_from(&mut self, other: &Self) { + if self.len() == other.len() { + self.clone_from_slice(&other); + } else { + *self = other.clone(); + } + } } #[stable(feature = "box_borrow", since = "1.1.0")] From 89aac165588b5b077ca8d747fee5c870c5b6e907 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 15:41:57 +0200 Subject: [PATCH 199/695] fix discriminant type in generator transform --- src/librustc_mir/transform/generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 5f8104e7934eb..50a882ab014fd 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -266,7 +266,7 @@ impl TransformVisitor<'tcx> { // Create a statement which reads the discriminant into a temporary fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) { - let temp_decl = LocalDecl::new(self.tcx.types.isize, body.span).internal(); + let temp_decl = LocalDecl::new(self.discr_ty, body.span).internal(); let local_decls_len = body.local_decls.push(temp_decl); let temp = Place::from(local_decls_len); From b388f964954aa17d2ed6d3f4519234df51280c91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 17:20:17 +0200 Subject: [PATCH 200/695] bless mir-opt tests --- .../rustc.main-{{closure}}.generator_drop.0.mir | 2 +- .../rustc.main-{{closure}}.generator_resume.0.mir | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir b/src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir index 382273a1e73e3..6a32a42d85a82 100644 --- a/src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir +++ b/src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir @@ -9,7 +9,7 @@ fn main::{{closure}}#0(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: let mut _5: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14 let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18 let mut _8: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 - let mut _9: isize; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 + let mut _9: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 scope 1 { debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 } diff --git a/src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir b/src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir index 75c2fb3d1307d..c73dea5f8fde6 100644 --- a/src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir +++ b/src/test/mir-opt/generator-tiny/rustc.main-{{closure}}.generator_resume.0.mir @@ -12,7 +12,7 @@ fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs: let _8: (); // in scope 0 at $DIR/generator-tiny.rs:23:13: 23:21 let mut _9: (); // in scope 0 at $DIR/generator-tiny.rs:19:25: 19:25 let _10: u8; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 - let mut _11: isize; // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 + let mut _11: u32; // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 scope 1 { debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15 } From 32eedadee1ed3273a318fa109c5261482e518578 Mon Sep 17 00:00:00 2001 From: mendess Date: Sat, 23 May 2020 16:51:02 +0100 Subject: [PATCH 201/695] Add tests --- src/liballoc/tests/boxed.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/liballoc/tests/boxed.rs b/src/liballoc/tests/boxed.rs index 66782ecbeb7f6..c0b8fa665615e 100644 --- a/src/liballoc/tests/boxed.rs +++ b/src/liballoc/tests/boxed.rs @@ -16,3 +16,39 @@ fn unitialized_zero_size_box() { NonNull::>::dangling().as_ptr(), ); } + +#[derive(Clone, PartialEq, Eq, Debug)] +struct Dummy { + _data: u8, +} + +#[test] +fn box_clone_and_clone_from_equivalence() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let clone = control.clone(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + copy.clone_from(&control); + assert_eq!(control, clone); + assert_eq!(control, copy); + } +} + +#[test] +fn box_clone_from_ptr_stability() { + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice(); + let copy_raw = copy.as_ptr() as usize; + copy.clone_from(&control); + assert_eq!(copy.as_ptr() as usize, copy_raw); + } + + for size in (0..8).map(|i| 2usize.pow(i)) { + let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); + let mut copy = vec![Dummy { _data: 84 }; size + 1].into_boxed_slice(); + let copy_raw = copy.as_ptr() as usize; + copy.clone_from(&control); + assert_ne!(copy.as_ptr() as usize, copy_raw); + } +} From f15e4b30c0d217b647e443333902ca7a948e0f58 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 19:02:26 +0200 Subject: [PATCH 202/695] fix Predicate perf regression --- src/librustc_infer/traits/util.rs | 30 ++++++++++++------------------ src/librustc_middle/ty/mod.rs | 7 +++++-- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 03f20c13068a8..17b7b4e680f5e 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -10,50 +10,44 @@ pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, pred: ty::Predicate<'tcx>, ) -> ty::Predicate<'tcx> { - match pred.kind() { + let kind = pred.kind(); + let new = match kind { &ty::PredicateKind::Trait(ref data, constness) => { ty::PredicateKind::Trait(tcx.anonymize_late_bound_regions(data), constness) - .to_predicate(tcx) } ty::PredicateKind::RegionOutlives(data) => { ty::PredicateKind::RegionOutlives(tcx.anonymize_late_bound_regions(data)) - .to_predicate(tcx) } ty::PredicateKind::TypeOutlives(data) => { ty::PredicateKind::TypeOutlives(tcx.anonymize_late_bound_regions(data)) - .to_predicate(tcx) } ty::PredicateKind::Projection(data) => { - ty::PredicateKind::Projection(tcx.anonymize_late_bound_regions(data)).to_predicate(tcx) + ty::PredicateKind::Projection(tcx.anonymize_late_bound_regions(data)) } - &ty::PredicateKind::WellFormed(data) => { - ty::PredicateKind::WellFormed(data).to_predicate(tcx) - } + &ty::PredicateKind::WellFormed(data) => ty::PredicateKind::WellFormed(data), - &ty::PredicateKind::ObjectSafe(data) => { - ty::PredicateKind::ObjectSafe(data).to_predicate(tcx) - } + &ty::PredicateKind::ObjectSafe(data) => ty::PredicateKind::ObjectSafe(data), &ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { - ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind).to_predicate(tcx) + ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) } ty::PredicateKind::Subtype(data) => { - ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data)).to_predicate(tcx) + ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data)) } &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { - ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(tcx) + ty::PredicateKind::ConstEvaluatable(def_id, substs) } - ty::PredicateKind::ConstEquate(c1, c2) => { - ty::PredicateKind::ConstEquate(c1, c2).to_predicate(tcx) - } - } + ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2), + }; + + if new != *kind { new.to_predicate(tcx) } else { pred } } struct PredicateSet<'tcx> { diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 877784bc50666..8fa7061998fd8 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1032,6 +1032,7 @@ impl<'tcx> PartialEq for Predicate<'tcx> { impl<'tcx> Eq for Predicate<'tcx> {} impl<'tcx> Predicate<'tcx> { + #[inline(always)] pub fn kind(self) -> &'tcx PredicateKind<'tcx> { self.kind } @@ -1166,7 +1167,8 @@ impl<'tcx> Predicate<'tcx> { // this trick achieves that). let substs = &trait_ref.skip_binder().substs; - let predicate = match self.kind() { + let kind = self.kind(); + let new = match kind { &PredicateKind::Trait(ref binder, constness) => { PredicateKind::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) } @@ -1195,7 +1197,7 @@ impl<'tcx> Predicate<'tcx> { } }; - predicate.to_predicate(tcx) + if new != *kind { new.to_predicate(tcx) } else { self } } } @@ -1314,6 +1316,7 @@ pub trait ToPredicate<'tcx> { } impl ToPredicate<'tcx> for PredicateKind<'tcx> { + #[inline(always)] fn to_predicate(&self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(*self) } From 3bf94b2c9d300132e391a27dfa6d44256ebee316 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 23 May 2020 18:49:38 +0100 Subject: [PATCH 203/695] Naming --- src/librustc_mir_build/hair/pattern/_match.rs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 928d1f6a68abc..32c54fbbfd9a6 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -1025,11 +1025,11 @@ enum Fields<'p, 'tcx> { /// have not measured if it really made a difference. Slice(&'p [Pat<'tcx>]), Vec(SmallVec<[&'p Pat<'tcx>; 2]>), - /// Patterns where some of the fields need to be hidden. `len` caches the number of non-hidden - /// fields. + /// Patterns where some of the fields need to be hidden. `kept_count` caches the number of + /// non-hidden fields. Filtered { fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>, - len: usize, + kept_count: usize, }, } @@ -1092,7 +1092,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { if has_no_hidden_fields { Fields::wildcards_from_tys(cx, field_tys) } else { - let mut len = 0; + let mut kept_count = 0; let fields = variant .fields .iter() @@ -1109,12 +1109,12 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { if is_uninhabited && (!is_visible || is_non_exhaustive) { FilteredField::Hidden(ty) } else { - len += 1; + kept_count += 1; FilteredField::Kept(wildcard_from_ty(ty)) } }) .collect(); - Fields::Filtered { fields, len } + Fields::Filtered { fields, kept_count } } } } @@ -1133,11 +1133,14 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { ret } + /// Returns the number of patterns from the viewpoint of match-checking, i.e. excluding hidden + /// fields. This is what we want in most cases in this file, the only exception being + /// conversion to/from `Pat`. fn len(&self) -> usize { match self { Fields::Slice(pats) => pats.len(), Fields::Vec(pats) => pats.len(), - Fields::Filtered { len, .. } => *len, + Fields::Filtered { kept_count, .. } => *kept_count, } } @@ -1207,7 +1210,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); match self { - Fields::Filtered { fields, len } => { + Fields::Filtered { fields, kept_count } => { let mut pats = pats.iter(); let mut fields = fields.clone(); for f in &mut fields { @@ -1216,7 +1219,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { *p = pats.next().unwrap(); } } - Fields::Filtered { fields, len: *len } + Fields::Filtered { fields, kept_count: *kept_count } } _ => Fields::Slice(pats), } From 7addc115eb18fb4a1e5347b55a138d0428fb6344 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 23 May 2020 18:59:27 +0100 Subject: [PATCH 204/695] Work around type normalization issues --- src/librustc_mir_build/hair/pattern/_match.rs | 4 +++- .../usefulness/issue-72476-associated-type.rs | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/pattern/usefulness/issue-72476-associated-type.rs diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 32c54fbbfd9a6..575ddcef99715 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -1870,7 +1870,9 @@ crate fn is_useful<'p, 'tcx>( return if any_is_useful { Useful(unreachable_pats) } else { NotUseful }; } - let pcx = PatCtxt { ty: v.head().ty, span: v.head().span }; + // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). + let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty); + let pcx = PatCtxt { ty, span: v.head().span }; debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head()); diff --git a/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs b/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs new file mode 100644 index 0000000000000..21ad6c7d989e0 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs @@ -0,0 +1,23 @@ +// check-pass + +// From https://github.com/rust-lang/rust/issues/72476 + +trait A { + type Projection; +} + +impl A for () { + type Projection = bool; + // using () instead of bool here does compile though +} + +struct Next(T::Projection); + +fn f(item: Next<()>) { + match item { + Next(true) => {} + Next(false) => {} + } +} + +fn main() {} From 3e8ba3a3cbf5d25352f95d93867a9fcda7d33e91 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 23 May 2020 19:39:38 +0100 Subject: [PATCH 205/695] Remove out-of-date comment --- src/test/ui/pattern/usefulness/issue-72476-associated-type.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs b/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs index 21ad6c7d989e0..1e1d21433b79c 100644 --- a/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs +++ b/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs @@ -8,7 +8,6 @@ trait A { impl A for () { type Projection = bool; - // using () instead of bool here does compile though } struct Next(T::Projection); From 8da494272f4c162c4a853e325a6bd33a80881ff6 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 May 2020 17:39:19 -0400 Subject: [PATCH 206/695] Add missing ASM arena declaration to librustc_middle Fixes #72386 This type also needs to get allocated on the `librustc_middle` arena when we deserialize MIR. --- src/librustc_middle/arena.rs | 6 ++++++ src/test/incremental/issue-72386.rs | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/test/incremental/issue-72386.rs diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index a97db3134dc9e..2df878c3fb220 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -76,6 +76,12 @@ macro_rules! arena_types { [few] hir_definitions: rustc_hir::definitions::Definitions, [] hir_owner: rustc_middle::hir::Owner<$tcx>, [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>, + + // Note that this deliberately duplicates items in the `rustc_hir::arena`, + // since we need to allocate this type on both the `rustc_hir` arena + // (during lowering) and the `librustc_middle` arena (for decoding MIR) + [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece, + ], $tcx); ) } diff --git a/src/test/incremental/issue-72386.rs b/src/test/incremental/issue-72386.rs new file mode 100644 index 0000000000000..3dc7f502a5992 --- /dev/null +++ b/src/test/incremental/issue-72386.rs @@ -0,0 +1,22 @@ +// revisions: rpass1 cfail1 rpass3 +// only-x86_64 +// Regression test for issue #72386 +// Checks that we don't ICE when switching to an invalid register +// and back again + +#![feature(asm)] + +#[cfg(any(rpass1, rpass3))] +fn main() { + unsafe { + asm!("nop") + } +} + +#[cfg(cfail1)] +fn main() { + unsafe { + asm!("nop",out("invalid_reg")_) + //[cfail1]~^ ERROR invalid register + } +} From 82b4fc42fdbbb1132f5a98ded198828e4175da66 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 24 May 2020 00:06:04 +0200 Subject: [PATCH 207/695] small select cleanup --- src/librustc_trait_selection/traits/select.rs | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index b402aba65cdb7..9b3381066a17b 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -1058,20 +1058,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Heuristics: show the diagnostics when there are no candidates in crate. if let Ok(candidate_set) = self.assemble_candidates(stack) { let mut no_candidates_apply = true; - { - let evaluated_candidates = - candidate_set.vec.iter().map(|c| self.evaluate_candidate(stack, &c)); - - for ec in evaluated_candidates { - match ec { - Ok(c) => { - if c.may_apply() { - no_candidates_apply = false; - break; - } - } - Err(e) => return Err(e.into()), - } + + for c in candidate_set.vec.iter() { + if self.evaluate_candidate(stack, &c)?.may_apply() { + no_candidates_apply = false; + break; } } @@ -3182,11 +3173,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { assert_eq!(tys_a.len(), tys_b.len()); // The last field of the tuple has to exist. - let (&a_last, a_mid) = if let Some(x) = tys_a.split_last() { - x - } else { - return Err(Unimplemented); - }; + let (&a_last, a_mid) = tys_a.split_last().ok_or(Unimplemented)?; let &b_last = tys_b.last().unwrap(); // Check that the source tuple with the target's From fbc6f2c70cf3d3cc3722cbd194e600d560d40758 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 10:30:33 +0200 Subject: [PATCH 208/695] make some cast helpers infallible --- src/librustc_mir/interpret/cast.rs | 46 +++++++++++------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 0e01652bc9002..c1ba9ae83dbba 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -106,14 +106,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match src.layout.ty.kind { // Floating point Float(FloatTy::F32) => { - return Ok(self - .cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty)? - .into()); + return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty).into()); } Float(FloatTy::F64) => { - return Ok(self - .cast_from_float(src.to_scalar()?.to_f64()?, dest_layout.ty)? - .into()); + return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, dest_layout.ty).into()); } // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that // are represented as integers. @@ -135,7 +131,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert!(src.layout.is_zst()); let discr_layout = self.layout_of(discr.ty)?; return Ok(self - .cast_from_int_like(discr.val, discr_layout, dest_layout)? + .cast_from_int_like(discr.val, discr_layout, dest_layout) .into()); } } @@ -173,15 +169,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // (b) cast from an integer-like (including bool, char, enums). // In both cases we want the bits. let bits = self.force_bits(src.to_scalar()?, src.layout.size)?; - Ok(self.cast_from_int_like(bits, src.layout, dest_layout)?.into()) + Ok(self.cast_from_int_like(bits, src.layout, dest_layout).into()) } - fn cast_from_int_like( + pub(super) fn cast_from_int_like( &self, v: u128, // raw bits src_layout: TyAndLayout<'tcx>, dest_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + ) -> Scalar { // Let's make sure v is sign-extended *if* it has a signed type. let signed = src_layout.abi.is_signed(); let v = if signed { self.sign_extend(v, src_layout) } else { v }; @@ -190,21 +186,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match dest_layout.ty.kind { Int(_) | Uint(_) | RawPtr(_) => { let v = self.truncate(v, dest_layout); - Ok(Scalar::from_uint(v, dest_layout.size)) + Scalar::from_uint(v, dest_layout.size) } - Float(FloatTy::F32) if signed => { - Ok(Scalar::from_f32(Single::from_i128(v as i128).value)) - } - Float(FloatTy::F64) if signed => { - Ok(Scalar::from_f64(Double::from_i128(v as i128).value)) - } - Float(FloatTy::F32) => Ok(Scalar::from_f32(Single::from_u128(v).value)), - Float(FloatTy::F64) => Ok(Scalar::from_f64(Double::from_u128(v).value)), + Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value), + Float(FloatTy::F64) if signed => Scalar::from_f64(Double::from_i128(v as i128).value), + Float(FloatTy::F32) => Scalar::from_f32(Single::from_u128(v).value), + Float(FloatTy::F64) => Scalar::from_f64(Double::from_u128(v).value), Char => { // `u8` to `char` cast - Ok(Scalar::from_u32(u8::try_from(v).unwrap().into())) + Scalar::from_u32(u8::try_from(v).unwrap().into()) } // Casts to bool are not permitted by rustc, no need to handle them here. @@ -212,11 +204,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - fn cast_from_float( - &self, - f: F, - dest_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, Scalar> + fn cast_from_float(&self, f: F, dest_ty: Ty<'tcx>) -> Scalar where F: Float + Into> + FloatConvert + FloatConvert, { @@ -229,7 +217,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). let v = f.to_u128(usize::try_from(width).unwrap()).value; // This should already fit the bit width - Ok(Scalar::from_uint(v, Size::from_bits(width))) + Scalar::from_uint(v, Size::from_bits(width)) } // float -> int Int(t) => { @@ -237,12 +225,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `to_i128` is a saturating cast, which is what we need // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). let v = f.to_i128(usize::try_from(width).unwrap()).value; - Ok(Scalar::from_int(v, Size::from_bits(width))) + Scalar::from_int(v, Size::from_bits(width)) } // float -> f32 - Float(FloatTy::F32) => Ok(Scalar::from_f32(f.convert(&mut false).value)), + Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value), // float -> f64 - Float(FloatTy::F64) => Ok(Scalar::from_f64(f.convert(&mut false).value)), + Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value), // That's it. _ => bug!("invalid float to {:?} cast", dest_ty), } From a709559705db19785b29ce4a9044d7aebaefec31 Mon Sep 17 00:00:00 2001 From: Nick Torres Date: Sat, 23 May 2020 16:14:38 -0700 Subject: [PATCH 209/695] Clarify the documentation of the `unnecessary_mut_passed` lint --- clippy_lints/src/mut_reference.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index e5680482e5bfb..67a1ac78a6777 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Detects giving a mutable reference to a function that only + /// **What it does:** Detects passing a mutable reference to a function that only /// requires an immutable reference. /// /// **Why is this bad?** The immutable reference rules out all other references From 3ed1e79cc40133b6cdb65955c7433cc483a89ca8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 24 May 2020 02:04:49 +0100 Subject: [PATCH 210/695] Properly handle InlineAsmOperand::SymFn when collecting monomorphized items Fixes #72484 --- src/librustc_codegen_ssa/mir/block.rs | 3 +- src/librustc_mir/monomorphize/collector.rs | 11 +++++-- src/test/ui/asm/sym.rs | 38 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/asm/sym.rs diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index b487ed8dea8b6..2a6d1abba9e9d 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -908,13 +908,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::InlineAsmOperand::SymFn { ref value } => { let literal = self.monomorphize(&value.literal); if let ty::FnDef(def_id, substs) = literal.ty.kind { - let instance = ty::Instance::resolve( + let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs, ) - .unwrap() .unwrap(); InlineAsmOperandRef::SymFn { instance } } else { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 925b8d329668f..3b05ffa567f86 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -633,14 +633,21 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let ty = self.monomorphize(ty); visit_drop_use(self.tcx, ty, true, self.output); } + mir::TerminatorKind::InlineAsm { ref operands, .. } => { + for op in operands { + if let mir::InlineAsmOperand::SymFn { value } = op { + let fn_ty = self.monomorphize(value.literal.ty); + visit_fn_use(self.tcx, fn_ty, false, &mut self.output); + } + } + } mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::Resume | mir::TerminatorKind::Abort | mir::TerminatorKind::Return | mir::TerminatorKind::Unreachable - | mir::TerminatorKind::Assert { .. } - | mir::TerminatorKind::InlineAsm { .. } => {} + | mir::TerminatorKind::Assert { .. } => {} mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Yield { .. } | mir::TerminatorKind::FalseEdges { .. } diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs new file mode 100644 index 0000000000000..83a3672af49ce --- /dev/null +++ b/src/test/ui/asm/sym.rs @@ -0,0 +1,38 @@ +// no-system-llvm +// only-x86_64 +// run-pass + +#![feature(asm, track_caller)] + +extern "C" fn f1() -> i32 { + 111 +} + +// The compiler will generate a shim to hide the caller location parameter. +#[track_caller] +fn f2() -> i32 { + 222 +} + +macro_rules! call { + ($func:path) => {{ + let result: i32; + unsafe { + asm!("call {}", sym $func, + out("rax") result, + out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _, + out("r8") _, out("r9") _, out("r10") _, out("r11") _, + out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _, + out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _, + out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _, + out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _, + ); + } + result + }} +} + +fn main() { + assert_eq!(call!(f1), 111); + assert_eq!(call!(f2), 222); +} From 235929953719661e70e152e63521a1c446d76caf Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 24 May 2020 02:57:21 +0200 Subject: [PATCH 211/695] Clear MIR local type annotations after borrowck --- src/librustc_mir/transform/cleanup_post_borrowck.rs | 4 ++++ src/test/incremental/hashes/let_expressions.rs | 2 +- .../32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir | 2 +- .../64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir | 2 +- .../const_prop/array_index/32bit/rustc.main.ConstProp.diff | 2 +- .../const_prop/array_index/64bit/rustc.main.ConstProp.diff | 2 +- .../32bit/rustc.main.ConstProp.diff | 2 +- .../64bit/rustc.main.ConstProp.diff | 2 +- .../mir-opt/const_prop/checked_add/rustc.main.ConstProp.diff | 2 +- .../rustc.main.ConstProp.diff | 2 +- .../mutable_variable_unprop_assign/rustc.main.ConstProp.diff | 2 +- .../mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff | 2 +- .../mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff | 2 +- .../inline/inline-into-box-place/32bit/rustc.main.Inline.diff | 2 +- .../inline/inline-into-box-place/64bit/rustc.main.Inline.diff | 2 +- .../retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir | 2 +- .../32bit/rustc.main.SimplifyArmIdentity.diff | 2 +- .../64bit/rustc.main.SimplifyArmIdentity.diff | 2 +- 18 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index e80da4f756c64..3f3d247a8294f 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -35,6 +35,10 @@ impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { let mut delete = DeleteNonCodegenStatements { tcx }; delete.visit_body(body); body.user_type_annotations.raw.clear(); + + for decl in &mut body.local_decls { + decl.user_ty = None; + } } } diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 924ed451e59f8..846bfc6d0e4db 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -38,7 +38,7 @@ pub fn add_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="hir_owner_nodes,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_nodes,typeck_tables_of,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn add_type() { let _x: u32 = 2u32; diff --git a/src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir index c42d5adce4f2b..d39b9b8a3b444 100644 --- a/src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/array-index-is-temporary/32bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir @@ -14,7 +14,7 @@ fn main() -> () { let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14 scope 2 { debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:14:9: 14:14 - let _3: *mut usize as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 2 at $DIR/array-index-is-temporary.rs:15:9: 15:10 + let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:15:9: 15:10 scope 3 { debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:15:9: 15:10 scope 4 { diff --git a/src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir index 05d9b3b9b6f77..381c1ca6f22ef 100644 --- a/src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/array-index-is-temporary/64bit/rustc.main.SimplifyCfg-elaborate-drops.after.mir @@ -14,7 +14,7 @@ fn main() -> () { let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:14:9: 14:14 scope 2 { debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:14:9: 14:14 - let _3: *mut usize as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 2 at $DIR/array-index-is-temporary.rs:15:9: 15:10 + let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:15:9: 15:10 scope 3 { debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:15:9: 15:10 scope 4 { diff --git a/src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff index e24751d39a7df..d02906132e296 100644 --- a/src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/array_index/32bit/rustc.main.ConstProp.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/array_index.rs:4:11: 4:11 - let _1: u32 as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/array_index.rs:5:9: 5:10 + let _1: u32; // in scope 0 at $DIR/array_index.rs:5:9: 5:10 let mut _2: [u32; 4]; // in scope 0 at $DIR/array_index.rs:5:18: 5:30 let _3: usize; // in scope 0 at $DIR/array_index.rs:5:31: 5:32 let mut _4: usize; // in scope 0 at $DIR/array_index.rs:5:18: 5:33 diff --git a/src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff index ad9992bb94905..4fe3f08955894 100644 --- a/src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/array_index/64bit/rustc.main.ConstProp.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/array_index.rs:4:11: 4:11 - let _1: u32 as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/array_index.rs:5:9: 5:10 + let _1: u32; // in scope 0 at $DIR/array_index.rs:5:9: 5:10 let mut _2: [u32; 4]; // in scope 0 at $DIR/array_index.rs:5:18: 5:30 let _3: usize; // in scope 0 at $DIR/array_index.rs:5:31: 5:32 let mut _4: usize; // in scope 0 at $DIR/array_index.rs:5:18: 5:33 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff index 8ecb77752bb39..7071f31dbf104 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:4:11: 4:11 - let _1: *const [i32] as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 + let _1: *const [i32]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 let mut _2: *const [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 let _3: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 let _4: [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:26: 5:35 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff index 2778ec02724df..15995ab070019 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:4:11: 4:11 - let _1: *const [i32] as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 + let _1: *const [i32]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:9: 5:10 let mut _2: *const [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 let _3: &[i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 let _4: [i32; 3]; // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:26: 5:35 diff --git a/src/test/mir-opt/const_prop/checked_add/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add/rustc.main.ConstProp.diff index 92add8bafdc03..f9f7d543d21f5 100644 --- a/src/test/mir-opt/const_prop/checked_add/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add/rustc.main.ConstProp.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/checked_add.rs:4:11: 4:11 - let _1: u32 as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/checked_add.rs:5:9: 5:10 + let _1: u32; // in scope 0 at $DIR/checked_add.rs:5:9: 5:10 let mut _2: (u32, bool); // in scope 0 at $DIR/checked_add.rs:5:18: 5:23 scope 1 { debug x => _1; // in scope 1 at $DIR/checked_add.rs:5:9: 5:10 diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff index 6834bb6bdd4f7..f6bb72baea419 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read/rustc.main.ConstProp.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:4:11: 4:11 - let mut _1: (i32, i32) as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14 + let mut _1: (i32, i32); // in scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14 scope 1 { debug x => _1; // in scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:5:9: 5:14 let _2: i32; // in scope 1 at $DIR/mutable_variable_aggregate_partial_read.rs:8:9: 8:10 diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff index 738343c655e36..e0b9fbe04c387 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign/rustc.main.ConstProp.diff @@ -7,7 +7,7 @@ let mut _3: i32; // in scope 0 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12 scope 1 { debug a => _1; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:5:9: 5:10 - let mut _2: (i32, i32) as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14 + let mut _2: (i32, i32); // in scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14 scope 2 { debug x => _2; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14 let _4: i32; // in scope 2 at $DIR/mutable_variable_unprop_assign.rs:8:9: 8:10 diff --git a/src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff index 4ccfe1838d9cc..b1c9e22913935 100644 --- a/src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/repeat/32bit/rustc.main.ConstProp.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/repeat.rs:5:11: 5:11 - let _1: u32 as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/repeat.rs:6:9: 6:10 + let _1: u32; // in scope 0 at $DIR/repeat.rs:6:9: 6:10 let mut _2: u32; // in scope 0 at $DIR/repeat.rs:6:18: 6:28 let mut _3: [u32; 8]; // in scope 0 at $DIR/repeat.rs:6:18: 6:25 let _4: usize; // in scope 0 at $DIR/repeat.rs:6:26: 6:27 diff --git a/src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff index fe9d16c4ffabb..29555b03a8b8e 100644 --- a/src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/repeat/64bit/rustc.main.ConstProp.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/repeat.rs:5:11: 5:11 - let _1: u32 as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/repeat.rs:6:9: 6:10 + let _1: u32; // in scope 0 at $DIR/repeat.rs:6:9: 6:10 let mut _2: u32; // in scope 0 at $DIR/repeat.rs:6:18: 6:28 let mut _3: [u32; 8]; // in scope 0 at $DIR/repeat.rs:6:18: 6:25 let _4: usize; // in scope 0 at $DIR/repeat.rs:6:26: 6:27 diff --git a/src/test/mir-opt/inline/inline-into-box-place/32bit/rustc.main.Inline.diff b/src/test/mir-opt/inline/inline-into-box-place/32bit/rustc.main.Inline.diff index 607dd468e598b..f31d5fae9ed37 100644 --- a/src/test/mir-opt/inline/inline-into-box-place/32bit/rustc.main.Inline.diff +++ b/src/test/mir-opt/inline/inline-into-box-place/32bit/rustc.main.Inline.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 - let _1: std::boxed::Box> as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 + let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 let mut _2: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 + let mut _4: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 diff --git a/src/test/mir-opt/inline/inline-into-box-place/64bit/rustc.main.Inline.diff b/src/test/mir-opt/inline/inline-into-box-place/64bit/rustc.main.Inline.diff index e83ca36706af7..324ec2d7c5bcd 100644 --- a/src/test/mir-opt/inline/inline-into-box-place/64bit/rustc.main.Inline.diff +++ b/src/test/mir-opt/inline/inline-into-box-place/64bit/rustc.main.Inline.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 - let _1: std::boxed::Box> as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 + let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 let mut _2: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 + let mut _4: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 diff --git a/src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir index f2154ef6b1e91..459c6b7a70a36 100644 --- a/src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir @@ -24,7 +24,7 @@ fn main() -> () { scope 1 { debug x => _1; // in scope 1 at $DIR/retag.rs:30:9: 30:14 let _3: &mut i32; // in scope 1 at $DIR/retag.rs:32:13: 32:14 - let _13: for<'r> fn(&'r i32) -> &'r i32 as UserTypeProjection { base: UserType(1), projs: [] }; // in scope 1 at $DIR/retag.rs:40:9: 40:10 + let _13: for<'r> fn(&'r i32) -> &'r i32; // in scope 1 at $DIR/retag.rs:40:9: 40:10 scope 2 { debug v => _3; // in scope 2 at $DIR/retag.rs:32:13: 32:14 let _8: &mut i32; // in scope 2 at $DIR/retag.rs:33:13: 33:14 diff --git a/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff index 6199e2c56625d..dfd6d6f0f2ecd 100644 --- a/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify-arm-identity/32bit/rustc.main.SimplifyArmIdentity.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11 - let _1: Src as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10 + let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10 let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6 let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20 let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34 diff --git a/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff index bf875c6a555fe..f2bbd19586993 100644 --- a/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify-arm-identity/64bit/rustc.main.SimplifyArmIdentity.diff @@ -3,7 +3,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:17:11: 17:11 - let _1: Src as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10 + let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10 let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:19:18: 22:6 let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:20:9: 20:20 let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:20:33: 20:34 From 58fdc43e03bd77c575bc1c62b18b784f71ab4bf2 Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Thu, 21 May 2020 23:01:22 +0200 Subject: [PATCH 212/695] NVPTX support for new asm! --- src/librustc_codegen_llvm/asm.rs | 12 +++ src/librustc_target/asm/mod.rs | 27 +++++++ src/librustc_target/asm/nvptx.rs | 90 ++++++++++++++++++++++ src/test/assembly/asm/nvptx-types.rs | 109 +++++++++++++++++++++++++++ 4 files changed, 238 insertions(+) create mode 100644 src/librustc_target/asm/nvptx.rs create mode 100644 src/test/assembly/asm/nvptx-types.rs diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index 8986ab322c07f..fe4cd16c1f5e5 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -254,6 +254,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { ]); } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} + InlineAsmArch::Nvptx64 => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -410,6 +411,11 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String { | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x", InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::freg32) => "f", + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::freg64) => "d", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", @@ -452,6 +458,7 @@ fn modifier_to_llvm( modifier } } + InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) @@ -502,6 +509,11 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { cx.type_vector(cx.type_i64(), 2) } + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::freg32) => cx.type_f32(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::freg64) => cx.type_f64(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index 774146a679ab8..ffca742e9ab8d 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -146,11 +146,13 @@ macro_rules! types { mod aarch64; mod arm; +mod nvptx; mod riscv; mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; +pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -162,6 +164,7 @@ pub enum InlineAsmArch { AArch64, RiscV32, RiscV64, + Nvptx64, } impl FromStr for InlineAsmArch { @@ -175,6 +178,7 @@ impl FromStr for InlineAsmArch { "aarch64" => Ok(Self::AArch64), "riscv32" => Ok(Self::RiscV32), "riscv64" => Ok(Self::RiscV64), + "nvptx64" => Ok(Self::Nvptx64), _ => Err(()), } } @@ -196,6 +200,7 @@ pub enum InlineAsmReg { Arm(ArmInlineAsmReg), AArch64(AArch64InlineAsmReg), RiscV(RiscVInlineAsmReg), + Nvptx(NvptxInlineAsmReg), } impl InlineAsmReg { @@ -205,6 +210,7 @@ impl InlineAsmReg { Self::Arm(r) => r.name(), Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), + Self::Nvptx(r) => r.name(), } } @@ -214,6 +220,7 @@ impl InlineAsmReg { Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()), Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), + Self::Nvptx(r) => InlineAsmRegClass::Nvptx(r.reg_class()), } } @@ -236,6 +243,9 @@ impl InlineAsmReg { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?) } + InlineAsmArch::Nvptx64 => { + Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?) + } }) } @@ -252,6 +262,7 @@ impl InlineAsmReg { Self::Arm(r) => r.emit(out, arch, modifier), Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), + Self::Nvptx(r) => r.emit(out, arch, modifier), } } @@ -261,6 +272,7 @@ impl InlineAsmReg { Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))), Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), + Self::Nvptx(_) => cb(self), } } } @@ -281,6 +293,7 @@ pub enum InlineAsmRegClass { Arm(ArmInlineAsmRegClass), AArch64(AArch64InlineAsmRegClass), RiscV(RiscVInlineAsmRegClass), + Nvptx(NvptxInlineAsmRegClass), } impl InlineAsmRegClass { @@ -290,6 +303,7 @@ impl InlineAsmRegClass { Self::Arm(r) => r.name(), Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), + Self::Nvptx(r) => r.name(), } } @@ -302,6 +316,7 @@ impl InlineAsmRegClass { Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm), Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64), Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), + Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), } } @@ -321,6 +336,7 @@ impl InlineAsmRegClass { Self::Arm(r) => r.suggest_modifier(arch, ty), Self::AArch64(r) => r.suggest_modifier(arch, ty), Self::RiscV(r) => r.suggest_modifier(arch, ty), + Self::Nvptx(r) => r.suggest_modifier(arch, ty), } } @@ -336,6 +352,7 @@ impl InlineAsmRegClass { Self::Arm(r) => r.default_modifier(arch), Self::AArch64(r) => r.default_modifier(arch), Self::RiscV(r) => r.default_modifier(arch), + Self::Nvptx(r) => r.default_modifier(arch), } } @@ -350,6 +367,7 @@ impl InlineAsmRegClass { Self::Arm(r) => r.supported_types(arch), Self::AArch64(r) => r.supported_types(arch), Self::RiscV(r) => r.supported_types(arch), + Self::Nvptx(r) => r.supported_types(arch), } } @@ -367,6 +385,9 @@ impl InlineAsmRegClass { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) } + InlineAsmArch::Nvptx64 => { + Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?) + } }) }) } @@ -379,6 +400,7 @@ impl InlineAsmRegClass { Self::Arm(r) => r.valid_modifiers(arch), Self::AArch64(r) => r.valid_modifiers(arch), Self::RiscV(r) => r.valid_modifiers(arch), + Self::Nvptx(r) => r.valid_modifiers(arch), } } } @@ -518,5 +540,10 @@ pub fn allocatable_registers( riscv::fill_reg_map(arch, has_feature, &mut map); map } + InlineAsmArch::Nvptx64 => { + let mut map = nvptx::regclass_map(); + nvptx::fill_reg_map(arch, has_feature, &mut map); + map + } } } diff --git a/src/librustc_target/asm/nvptx.rs b/src/librustc_target/asm/nvptx.rs new file mode 100644 index 0000000000000..b574e921718ad --- /dev/null +++ b/src/librustc_target/asm/nvptx.rs @@ -0,0 +1,90 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + Nvptx NvptxInlineAsmRegClass { + reg16, + reg32, + reg64, + freg32, + freg64, + } +} + +impl NvptxInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: 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<&'static str>)] { + match self { + Self::reg16 => types! { _: I8, I16; }, + Self::reg32 => types! { _: I8, I16, I32; }, + Self::reg64 => types! { _: I8, I16, I32, I64; }, + Self::freg32 => types! { _: F32; }, + Self::freg64 => types! { _: F32, F64; }, + } + } +} + +def_regs! { + Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass { + // We have to define a register, otherwise we get warnings/errors about unused imports and + // unreachable code. Do what clang does and define r0. + r0: reg32 = ["r0"], + #error = ["tid", "tid.x", "tid.y", "tid.z"] => "tid not supported for inline asm", + #error = ["ntid", "ntid.x", "ntid.y", "ntid.z"] => "ntid not supported for inline asm", + #error = ["laneid"] => "laneid not supported for inline asm", + #error = ["warpid"] => "warpid not supported for inline asm", + #error = ["nwarpid"] => "nwarpid not supported for inline asm", + #error = ["ctaid", "ctaid.x", "ctaid.y", "ctaid.z"] => "ctaid not supported for inline asm", + #error = ["nctaid", "nctaid.x", "nctaid.y", "nctaid.z"] => "nctaid not supported for inline asm", + #error = ["smid"] => "smid not supported for inline asm", + #error = ["nsmid"] => "nsmid not supported for inline asm", + #error = ["gridid"] => "gridid not supported for inline asm", + #error = ["lanemask_eq"] => "lanemask_eq not supported for inline asm", + #error = ["lanemask_le"] => "lanemask_le not supported for inline asm", + #error = ["lanemask_lt"] => "lanemask_lt not supported for inline asm", + #error = ["lanemask_ge"] => "lanemask_ge not supported for inline asm", + #error = ["lanemask_gt"] => "lanemask_gt not supported for inline asm", + #error = ["clock", "clock_hi"] => "clock not supported for inline asm", + #error = ["clock64"] => "clock64 not supported for inline asm", + #error = ["pm0", "pm1", "pm2", "pm3", "pm4", "pm5", "pm6", "pm7"] => "pm not supported for inline asm", + #error = ["pm0_64", "pm1_64", "pm2_64", "pm3_64", "pm4_64", "pm5_64", "pm6_64", "pm7_64"] => "pm_64 not supported for inline asm", + #error = ["envreg0", "envreg1", "envreg2", "envreg3", "envreg4", "envreg5", "envreg6", "envreg7", "envreg8", "envreg9", "envreg10", "envreg11", "envreg12", "envreg13", "envreg14", "envreg15", "envreg16", "envreg17", "envreg18", "envreg19", "envreg20", "envreg21", "envreg22", "envreg23", "envreg24", "envreg25", "envreg26", "envreg27", "envreg28", "envreg29", "envreg30", "envreg31"] => "envreg not supported for inline asm", + #error = ["globaltimer", "globaltimer_lo", "globaltimer_hi"] => "globaltimer not supported for inline asm", + #error = ["total_mem_size"] => "total_mem_size not supported for inline asm", + #error = ["dynamic_mem_size"] => "dynamic_mem_size not supported for inline asm", + } +} + +impl NvptxInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs new file mode 100644 index 0000000000000..cfaab23512458 --- /dev/null +++ b/src/test/assembly/asm/nvptx-types.rs @@ -0,0 +1,109 @@ +// no-system-llvm +// assembly-output: emit-asm +// compile-flags: --target --nvptx64-nvidia-cuda +// only-nvptx64 +// ignore-nvptx64 + +#![feature(no_core, lang_items, rustc_attrs)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *mut u8; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for i64 {} +impl Copy for f64 {} +impl Copy for ptr {} + +#[no_mangle] +fn extern_func(); + +// CHECK-LABEL: sym_fn +// CHECK: #APP +// CHECK call extern_func; +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +macro_rules! check { + ($func:ident $ty:ident, $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: reg_i8 +// CHECK: #APP +// CHECK: mov.i16 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg_i8 i8 reg16 "mov.i16"); + +// CHECK-LABEL: reg_i16 +// CHECK: #APP +// CHECK: mov.i16 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg_i16 i16 reg16 "mov.i16"); + +// CHECK-LABEL: reg_i32 +// CHECK: #APP +// CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg_i32 i32 reg32 "mov.i32"); + +// CHECK-LABEL: reg_f32 +// CHECK: #APP +// CHECK: mov.f32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg_f32 f32 freg32 "mov.f32"); + +// CHECK-LABEL: reg_i54 +// CHECK: #APP +// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg_i64 i64 reg64 "mov.i64"); + +// CHECK-LABEL: reg_f64 +// CHECK: #APP +// CHECK: mov.f64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg_f64 f64 freg64 "mov.f64"); + +// CHECK-LABEL: reg_ptr +// CHECK: #APP +// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg_ptr ptr reg64 "mov.i64"); From d77f73e8818453afd513f96e98cf7e0c889cdbd9 Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Fri, 22 May 2020 00:31:50 +0200 Subject: [PATCH 213/695] Formatted correctly --- src/librustc_target/asm/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index ffca742e9ab8d..99061d1fdeb8b 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -385,9 +385,7 @@ impl InlineAsmRegClass { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) } - InlineAsmArch::Nvptx64 => { - Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?) - } + InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), }) }) } From baa801a92900d1a44ab5efb005b4bbb0353af206 Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Fri, 22 May 2020 14:38:46 +0200 Subject: [PATCH 214/695] Minor fixes, as requested in PR review --- src/librustc_codegen_llvm/asm.rs | 4 -- src/librustc_target/asm/mod.rs | 28 +++++++++-- src/librustc_target/asm/nvptx.rs | 49 ++---------------- src/test/assembly/asm/nvptx-types.rs | 75 ++++++++++++++++++++-------- 4 files changed, 80 insertions(+), 76 deletions(-) diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index fe4cd16c1f5e5..f3b46dd322a39 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -414,8 +414,6 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String { InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::freg32) => "f", - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::freg64) => "d", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r", InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", @@ -512,8 +510,6 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::freg32) => cx.type_f32(), - InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::freg64) => cx.type_f64(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index 99061d1fdeb8b..1bbaa4c4c002e 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -52,6 +52,30 @@ macro_rules! def_reg_class { #[macro_use] macro_rules! def_regs { + ($arch:ident $arch_reg:ident $arch_regclass:ident {}) => { + #[allow(unreachable_code)] + #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] + pub enum $arch_reg {} + + impl $arch_reg { + pub fn parse( + _arch: super::InlineAsmArch, + mut _has_feature: impl FnMut(&str) -> bool, + _name: &str, + ) -> Result { + Err("unknown register") + } + } + + pub(super) fn fill_reg_map( + _arch: super::InlineAsmArch, + mut _has_feature: impl FnMut(&str) -> bool, + _map: &mut rustc_data_structures::fx::FxHashMap< + super::InlineAsmRegClass, + rustc_data_structures::fx::FxHashSet, + >, + ) {} + }; ($arch:ident $arch_reg:ident $arch_regclass:ident { $( $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?, @@ -210,7 +234,6 @@ impl InlineAsmReg { Self::Arm(r) => r.name(), Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), - Self::Nvptx(r) => r.name(), } } @@ -220,7 +243,6 @@ impl InlineAsmReg { Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()), Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), - Self::Nvptx(r) => InlineAsmRegClass::Nvptx(r.reg_class()), } } @@ -262,7 +284,6 @@ impl InlineAsmReg { Self::Arm(r) => r.emit(out, arch, modifier), Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), - Self::Nvptx(r) => r.emit(out, arch, modifier), } } @@ -272,7 +293,6 @@ impl InlineAsmReg { Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))), Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), - Self::Nvptx(_) => cb(self), } } } diff --git a/src/librustc_target/asm/nvptx.rs b/src/librustc_target/asm/nvptx.rs index b574e921718ad..cba069cd0542c 100644 --- a/src/librustc_target/asm/nvptx.rs +++ b/src/librustc_target/asm/nvptx.rs @@ -1,14 +1,11 @@ use super::{InlineAsmArch, InlineAsmType}; use rustc_macros::HashStable_Generic; -use std::fmt; def_reg_class! { Nvptx NvptxInlineAsmRegClass { reg16, reg32, reg64, - freg32, - freg64, } } @@ -39,52 +36,12 @@ impl NvptxInlineAsmRegClass { ) -> &'static [(InlineAsmType, Option<&'static str>)] { match self { Self::reg16 => types! { _: I8, I16; }, - Self::reg32 => types! { _: I8, I16, I32; }, - Self::reg64 => types! { _: I8, I16, I32, I64; }, - Self::freg32 => types! { _: F32; }, - Self::freg64 => types! { _: F32, F64; }, + Self::reg32 => types! { _: I8, I16, I32, F32; }, + Self::reg64 => types! { _: I8, I16, I32, F32, I64, F64; }, } } } def_regs! { - Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass { - // We have to define a register, otherwise we get warnings/errors about unused imports and - // unreachable code. Do what clang does and define r0. - r0: reg32 = ["r0"], - #error = ["tid", "tid.x", "tid.y", "tid.z"] => "tid not supported for inline asm", - #error = ["ntid", "ntid.x", "ntid.y", "ntid.z"] => "ntid not supported for inline asm", - #error = ["laneid"] => "laneid not supported for inline asm", - #error = ["warpid"] => "warpid not supported for inline asm", - #error = ["nwarpid"] => "nwarpid not supported for inline asm", - #error = ["ctaid", "ctaid.x", "ctaid.y", "ctaid.z"] => "ctaid not supported for inline asm", - #error = ["nctaid", "nctaid.x", "nctaid.y", "nctaid.z"] => "nctaid not supported for inline asm", - #error = ["smid"] => "smid not supported for inline asm", - #error = ["nsmid"] => "nsmid not supported for inline asm", - #error = ["gridid"] => "gridid not supported for inline asm", - #error = ["lanemask_eq"] => "lanemask_eq not supported for inline asm", - #error = ["lanemask_le"] => "lanemask_le not supported for inline asm", - #error = ["lanemask_lt"] => "lanemask_lt not supported for inline asm", - #error = ["lanemask_ge"] => "lanemask_ge not supported for inline asm", - #error = ["lanemask_gt"] => "lanemask_gt not supported for inline asm", - #error = ["clock", "clock_hi"] => "clock not supported for inline asm", - #error = ["clock64"] => "clock64 not supported for inline asm", - #error = ["pm0", "pm1", "pm2", "pm3", "pm4", "pm5", "pm6", "pm7"] => "pm not supported for inline asm", - #error = ["pm0_64", "pm1_64", "pm2_64", "pm3_64", "pm4_64", "pm5_64", "pm6_64", "pm7_64"] => "pm_64 not supported for inline asm", - #error = ["envreg0", "envreg1", "envreg2", "envreg3", "envreg4", "envreg5", "envreg6", "envreg7", "envreg8", "envreg9", "envreg10", "envreg11", "envreg12", "envreg13", "envreg14", "envreg15", "envreg16", "envreg17", "envreg18", "envreg19", "envreg20", "envreg21", "envreg22", "envreg23", "envreg24", "envreg25", "envreg26", "envreg27", "envreg28", "envreg29", "envreg30", "envreg31"] => "envreg not supported for inline asm", - #error = ["globaltimer", "globaltimer_lo", "globaltimer_hi"] => "globaltimer not supported for inline asm", - #error = ["total_mem_size"] => "total_mem_size not supported for inline asm", - #error = ["dynamic_mem_size"] => "dynamic_mem_size not supported for inline asm", - } -} - -impl NvptxInlineAsmReg { - pub fn emit( - self, - out: &mut dyn fmt::Write, - _arch: InlineAsmArch, - _modifier: Option, - ) -> fmt::Result { - out.write_str(self.name()) - } + Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass {} } diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs index cfaab23512458..5faf4082f327c 100644 --- a/src/test/assembly/asm/nvptx-types.rs +++ b/src/test/assembly/asm/nvptx-types.rs @@ -1,6 +1,7 @@ // no-system-llvm // assembly-output: emit-asm // compile-flags: --target --nvptx64-nvidia-cuda +// compile-flags: -Z merge-functions=disabled // only-nvptx64 // ignore-nvptx64 @@ -53,12 +54,6 @@ macro_rules! check { ($func:ident $ty:ident, $class:ident $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { - // Hack to avoid function merging - extern "Rust" { - fn dont_merge(s: &str); - } - dont_merge(stringify!($func)); - let y; asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x); y @@ -66,44 +61,80 @@ macro_rules! check { }; } -// CHECK-LABEL: reg_i8 +// CHECK-LABEL: reg16_i8 // CHECK: #APP // CHECK: mov.i16 {{[a-z0-9]+}}, {{[a-z0-9]+}}; // CHECK: #NO_APP -check!(reg_i8 i8 reg16 "mov.i16"); +check!(reg16_i8 i8 reg16 "mov.i16"); -// CHECK-LABEL: reg_i16 +// CHECK-LABEL: reg16_i16 // CHECK: #APP // CHECK: mov.i16 {{[a-z0-9]+}}, {{[a-z0-9]+}}; // CHECK: #NO_APP -check!(reg_i16 i16 reg16 "mov.i16"); +check!(reg16_i16 i16 reg16 "mov.i16"); + +// CHECK-LABEL: reg32_i8 +// CHECK: #APP +// CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg32_i8 i8 reg32 "mov.i32"); + +// CHECK-LABEL: reg32_i16 +// CHECK: #APP +// CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg32_i16 i16 reg32 "mov.i32"); -// CHECK-LABEL: reg_i32 +// CHECK-LABEL: reg32_i32 // CHECK: #APP // CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; // CHECK: #NO_APP -check!(reg_i32 i32 reg32 "mov.i32"); +check!(reg32_i32 i32 reg32 "mov.i32"); -// CHECK-LABEL: reg_f32 +// CHECK-LABEL: reg32_f32 // CHECK: #APP -// CHECK: mov.f32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg32_f32 f32 reg32 "mov.i32"); + +// CHECK-LABEL: reg64_i8 +// CHECK: #APP +// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; // CHECK: #NO_APP -check!(reg_f32 f32 freg32 "mov.f32"); +check!(reg64_i8 i8 reg64 "mov.i64"); -// CHECK-LABEL: reg_i54 +// CHECK-LABEL: reg64_i16 // CHECK: #APP // CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; // CHECK: #NO_APP -check!(reg_i64 i64 reg64 "mov.i64"); +check!(reg64_i16 i16 reg64 "mov.i64"); -// CHECK-LABEL: reg_f64 +// CHECK-LABEL: reg64_i32 // CHECK: #APP -// CHECK: mov.f64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg64_i32 i32 reg64 "mov.i64"); + +// CHECK-LABEL: reg64_f32 +// CHECK: #APP +// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg64_f32 f32 reg64 "mov.i64"); + +// CHECK-LABEL: reg64_i64 +// CHECK: #APP +// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; +// CHECK: #NO_APP +check!(reg64_i64 i64 reg64 "mov.i64"); + +// CHECK-LABEL: reg64_f64 +// CHECK: #APP +// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; // CHECK: #NO_APP -check!(reg_f64 f64 freg64 "mov.f64"); +check!(reg64_f64 f64 reg64 "mov.i64"); -// CHECK-LABEL: reg_ptr +// CHECK-LABEL: reg64_ptr // CHECK: #APP // CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; // CHECK: #NO_APP -check!(reg_ptr ptr reg64 "mov.i64"); +check!(reg64_ptr ptr reg64 "mov.i64"); From 1070f08aaba30cfe2aba587a911fcbdf35f6cdbc Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Fri, 22 May 2020 18:16:26 +0200 Subject: [PATCH 215/695] Deduplicated macro code --- src/librustc_target/asm/mod.rs | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index 1bbaa4c4c002e..a18a4dbd3e214 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -52,30 +52,6 @@ macro_rules! def_reg_class { #[macro_use] macro_rules! def_regs { - ($arch:ident $arch_reg:ident $arch_regclass:ident {}) => { - #[allow(unreachable_code)] - #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] - pub enum $arch_reg {} - - impl $arch_reg { - pub fn parse( - _arch: super::InlineAsmArch, - mut _has_feature: impl FnMut(&str) -> bool, - _name: &str, - ) -> Result { - Err("unknown register") - } - } - - pub(super) fn fill_reg_map( - _arch: super::InlineAsmArch, - mut _has_feature: impl FnMut(&str) -> bool, - _map: &mut rustc_data_structures::fx::FxHashMap< - super::InlineAsmRegClass, - rustc_data_structures::fx::FxHashSet, - >, - ) {} - }; ($arch:ident $arch_reg:ident $arch_regclass:ident { $( $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?, @@ -84,6 +60,7 @@ macro_rules! def_regs { #error = [$($bad_reg:literal),+] => $error:literal, )* }) => { + #[allow(unreachable_code)] #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] #[allow(non_camel_case_types)] pub enum $arch_reg { @@ -126,19 +103,20 @@ macro_rules! def_regs { pub(super) fn fill_reg_map( _arch: super::InlineAsmArch, mut _has_feature: impl FnMut(&str) -> bool, - map: &mut rustc_data_structures::fx::FxHashMap< + _map: &mut rustc_data_structures::fx::FxHashMap< super::InlineAsmRegClass, rustc_data_structures::fx::FxHashSet, >, ) { + #[allow(unused_imports)] use super::{InlineAsmReg, InlineAsmRegClass}; $( if $($filter(_arch, &mut _has_feature, true).is_ok() &&)? true { - if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) { + if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) { set.insert(InlineAsmReg::$arch($arch_reg::$reg)); } $( - if let Some(set) = map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) { + if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$extra_class)) { set.insert(InlineAsmReg::$arch($arch_reg::$reg)); } )* From 6d74e096d868385441874346c0eab93bc405ebef Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Fri, 22 May 2020 18:16:57 +0200 Subject: [PATCH 216/695] Added comment on there being no predefined registers --- src/librustc_target/asm/nvptx.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_target/asm/nvptx.rs b/src/librustc_target/asm/nvptx.rs index cba069cd0542c..43d16ae0f5d10 100644 --- a/src/librustc_target/asm/nvptx.rs +++ b/src/librustc_target/asm/nvptx.rs @@ -43,5 +43,7 @@ impl NvptxInlineAsmRegClass { } def_regs! { + // Registers in PTX are declared in the assembly. + // There are no predefined registers that one can use. Nvptx NvptxInlineAsmReg NvptxInlineAsmRegClass {} } From 5ec6b5eaeed5cddcb224cdec7bda148b3c8631f4 Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Fri, 22 May 2020 18:17:22 +0200 Subject: [PATCH 217/695] Fixed tests --- src/test/assembly/asm/nvptx-types.rs | 130 +++++++++++++-------------- 1 file changed, 61 insertions(+), 69 deletions(-) diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs index 5faf4082f327c..b36efe16c64a1 100644 --- a/src/test/assembly/asm/nvptx-types.rs +++ b/src/test/assembly/asm/nvptx-types.rs @@ -1,14 +1,10 @@ // no-system-llvm // assembly-output: emit-asm -// compile-flags: --target --nvptx64-nvidia-cuda -// compile-flags: -Z merge-functions=disabled -// only-nvptx64 -// ignore-nvptx64 +// compile-flags: --target nvptx64-nvidia-cuda +// compile-flags: --crate-type cdylib #![feature(no_core, lang_items, rustc_attrs)] -#![crate_type = "rlib"] #![no_core] -#![allow(asm_sub_register, non_camel_case_types)] #[rustc_builtin_macro] macro_rules! asm { @@ -18,10 +14,6 @@ macro_rules! asm { macro_rules! concat { () => {}; } -#[rustc_builtin_macro] -macro_rules! stringify { - () => {}; -} #[lang = "sized"] trait Sized {} @@ -39,19 +31,19 @@ impl Copy for f64 {} impl Copy for ptr {} #[no_mangle] -fn extern_func(); +fn extern_func() {} -// CHECK-LABEL: sym_fn -// CHECK: #APP -// CHECK call extern_func; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func sym_fn() +// CHECK: // begin inline asm +// CHECK: call extern_func; +// CHECK: // end inline asm #[no_mangle] pub unsafe fn sym_fn() { - asm!("call {}", sym extern_func); + asm!("call {};", sym extern_func); } macro_rules! check { - ($func:ident $ty:ident, $class:ident $mov:literal) => { + ($func:ident $ty:ident $class:ident $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { let y; @@ -61,80 +53,80 @@ macro_rules! check { }; } -// CHECK-LABEL: reg16_i8 -// CHECK: #APP -// CHECK: mov.i16 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i8 +// CHECK: // begin inline asm +// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg16_i8 i8 reg16 "mov.i16"); -// CHECK-LABEL: reg16_i16 -// CHECK: #APP -// CHECK: mov.i16 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i16 +// CHECK: // begin inline asm +// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg16_i16 i16 reg16 "mov.i16"); -// CHECK-LABEL: reg32_i8 -// CHECK: #APP -// CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i8 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg32_i8 i8 reg32 "mov.i32"); -// CHECK-LABEL: reg32_i16 -// CHECK: #APP -// CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i16 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg32_i16 i16 reg32 "mov.i32"); -// CHECK-LABEL: reg32_i32 -// CHECK: #APP -// CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i32 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg32_i32 i32 reg32 "mov.i32"); -// CHECK-LABEL: reg32_f32 -// CHECK: #APP -// CHECK: mov.i32 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_f32 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg32_f32 f32 reg32 "mov.i32"); -// CHECK-LABEL: reg64_i8 -// CHECK: #APP -// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i8 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg64_i8 i8 reg64 "mov.i64"); -// CHECK-LABEL: reg64_i16 -// CHECK: #APP -// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i16 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg64_i16 i16 reg64 "mov.i64"); -// CHECK-LABEL: reg64_i32 -// CHECK: #APP -// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i32 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg64_i32 i32 reg64 "mov.i64"); -// CHECK-LABEL: reg64_f32 -// CHECK: #APP -// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_f32 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg64_f32 f32 reg64 "mov.i64"); -// CHECK-LABEL: reg64_i64 -// CHECK: #APP -// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_i64 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg64_i64 i64 reg64 "mov.i64"); -// CHECK-LABEL: reg64_f64 -// CHECK: #APP -// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_f64 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg64_f64 f64 reg64 "mov.i64"); -// CHECK-LABEL: reg64_ptr -// CHECK: #APP -// CHECK: mov.i64 {{[a-z0-9]+}}, {{[a-z0-9]+}}; -// CHECK: #NO_APP +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_ptr +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm check!(reg64_ptr ptr reg64 "mov.i64"); From ed559b3770d11f1047f0f4df3036beccb1b6dc47 Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Sat, 23 May 2020 00:25:20 +0200 Subject: [PATCH 218/695] Updated documentation --- src/doc/unstable-book/src/library-features/asm.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 0b68991fce2a1..c34a2931bc06b 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -468,12 +468,17 @@ Here is the list of currently supported register classes: | ARM | `qreg` | `q[0-15]` | `w` | | ARM | `qreg_low8` | `q[0-7]` | `t` | | ARM | `qreg_low4` | `q[0-3]` | `x` | +| NVPTX | `reg16` | None\* | `h` | +| NVPTX | `reg32` | None\* | `r` | +| NVPTX | `reg64` | None\* | `l` | | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` | | RISC-V | `freg` | `f[0-31]` | `f` | > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. > > Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register. +> +> Note #3: On NVPTX, register names are not supported. Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc). @@ -495,6 +500,9 @@ Each register class has constraints on which value types they can be used with. | ARM | `sreg` | `vfp2` | `i32`, `f32` | | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` | | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` | +| NVPTX | `reg16` | None | `i8`, `i16` | +| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | +| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | | RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | RISC-V | `freg` | `f` | `f32` | @@ -502,7 +510,7 @@ Each register class has constraints on which value types they can be used with. > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). -If a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exception is the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture. +If a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exceptions are the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture, and the register classes on NVPTX where values are zero-extended. When separate input and output expressions are specified for an `inout` operand, both expressions must have the same type. The only exception is if both operands are pointers or integers, in which case they are only required to have the same size. This restriction exists because the register allocators in LLVM and GCC sometimes cannot handle tied operands with different types. @@ -610,6 +618,9 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | ARM | `dreg` | None | `d0` | `P` | | ARM | `qreg` | None | `q0` | `q` | | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` | +| NVPTX | `reg16` | None | `rs0` | None | +| NVPTX | `reg32` | None | `r0` | None | +| NVPTX | `reg64` | None | `rd0` | None | | RISC-V | `reg` | None | `x1` | None | | RISC-V | `freg` | None | `f0` | None | From 70cd375c57bc35db9c9a3eff37abdb900e45f910 Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Sat, 23 May 2020 03:48:40 +0200 Subject: [PATCH 219/695] Corrected statement about zero-extension in docs. --- src/doc/unstable-book/src/library-features/asm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index c34a2931bc06b..50121b2c0fca4 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -510,7 +510,7 @@ Each register class has constraints on which value types they can be used with. > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). -If a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exceptions are the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture, and the register classes on NVPTX where values are zero-extended. +If a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exception is the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture. When separate input and output expressions are specified for an `inout` operand, both expressions must have the same type. The only exception is if both operands are pointers or integers, in which case they are only required to have the same size. This restriction exists because the register allocators in LLVM and GCC sometimes cannot handle tied operands with different types. From 83a5cdf0aec1a998fed98565829ee7b732b95134 Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Sat, 23 May 2020 03:55:34 +0200 Subject: [PATCH 220/695] Update src/doc/unstable-book/src/library-features/asm.md Co-authored-by: Amanieu d'Antras --- src/doc/unstable-book/src/library-features/asm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 50121b2c0fca4..ea560a6d70915 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -478,7 +478,7 @@ Here is the list of currently supported register classes: > > Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register. > -> Note #3: On NVPTX, register names are not supported. +> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported. Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc). From e18054d5c07c2303380b47c3ea21f5bd7cccddc9 Mon Sep 17 00:00:00 2001 From: Michal Sudwoj Date: Sat, 23 May 2020 13:13:17 +0200 Subject: [PATCH 221/695] Added comment about static variables --- src/test/assembly/asm/nvptx-types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs index b36efe16c64a1..4ee79d1bcc839 100644 --- a/src/test/assembly/asm/nvptx-types.rs +++ b/src/test/assembly/asm/nvptx-types.rs @@ -30,6 +30,7 @@ impl Copy for i64 {} impl Copy for f64 {} impl Copy for ptr {} +// NVPTX does not support static variables #[no_mangle] fn extern_func() {} From b97ed1a46c8b7531435f8728ad66ca1d3fa4bef4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 09:38:29 +0200 Subject: [PATCH 222/695] Miri casts: do not blindly rely on dest type --- src/librustc_mir/interpret/cast.rs | 122 +++++++++++++++++------------ src/librustc_mir/interpret/step.rs | 5 +- 2 files changed, 76 insertions(+), 51 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index c1ba9ae83dbba..18483c70951b4 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -1,6 +1,5 @@ use std::convert::TryFrom; -use super::{FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy}; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_ast::ast::FloatTy; @@ -12,25 +11,40 @@ use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable}; use rustc_span::symbol::sym; use rustc_target::abi::{LayoutOf, Size, Variants}; +use super::{truncate, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy}; + impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn cast( &mut self, src: OpTy<'tcx, M::PointerTag>, - kind: CastKind, + cast_kind: CastKind, + cast_ty: Ty<'tcx>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { use rustc_middle::mir::CastKind::*; - match kind { + // FIXME: In which cases should we trigger UB when the source is uninit? + match cast_kind { Pointer(PointerCast::Unsize) => { + assert_eq!( + cast_ty, dest.layout.ty, + "mismatch of cast type {} and place type {}", + cast_ty, dest.layout.ty + ); self.unsize_into(src, dest)?; } - Misc | Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer) => { + Misc => { let src = self.read_immediate(src)?; - let res = self.cast_immediate(src, dest.layout)?; + let res = self.misc_cast(src, cast_ty)?; self.write_immediate(res, dest)?; } + Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer) => { + // These are NOPs, but can be wide pointers. + let v = self.read_immediate(src)?; + self.write_immediate(*v, dest)?; + } + Pointer(PointerCast::ReifyFnPointer) => { // The src operand does not matter, just its type match src.layout.ty.kind { @@ -61,12 +75,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::UnsafeFnPointer) => { let src = self.read_immediate(src)?; - match dest.layout.ty.kind { + match cast_ty.kind { ty::FnPtr(_) => { // No change to value self.write_immediate(*src, dest)?; } - _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty), + _ => bug!("fn to unsafe fn cast on {:?}", cast_ty), } } @@ -95,21 +109,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - fn cast_immediate( + fn misc_cast( &self, src: ImmTy<'tcx, M::PointerTag>, - dest_layout: TyAndLayout<'tcx>, + cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Immediate> { use rustc_middle::ty::TyKind::*; - trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty); + trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); match src.layout.ty.kind { // Floating point Float(FloatTy::F32) => { - return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty).into()); + return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into()); } Float(FloatTy::F64) => { - return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, dest_layout.ty).into()); + return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into()); } // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that // are represented as integers. @@ -124,69 +138,79 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ), } + // # First handle non-scalar source values. + // Handle cast from a univariant (ZST) enum. match src.layout.variants { Variants::Single { index } => { if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) { assert!(src.layout.is_zst()); let discr_layout = self.layout_of(discr.ty)?; - return Ok(self - .cast_from_int_like(discr.val, discr_layout, dest_layout) - .into()); + return Ok(self.cast_from_scalar(discr.val, discr_layout, cast_ty).into()); } } Variants::Multiple { .. } => {} } - // Handle casting the metadata away from a fat pointer. - if src.layout.ty.is_unsafe_ptr() - && dest_layout.ty.is_unsafe_ptr() - && dest_layout.size != src.layout.size - { - assert_eq!(src.layout.size, 2 * self.memory.pointer_size()); - assert_eq!(dest_layout.size, self.memory.pointer_size()); - assert!(dest_layout.ty.is_unsafe_ptr()); - match *src { - Immediate::ScalarPair(data, _) => return Ok(data.into()), - Immediate::Scalar(..) => bug!( - "{:?} input to a fat-to-thin cast ({:?} -> {:?})", - *src, - src.layout.ty, - dest_layout.ty - ), - }; - } - // Handle casting any ptr to raw ptr (might be a fat ptr). - if src.layout.ty.is_any_ptr() && dest_layout.ty.is_unsafe_ptr() { - // The only possible size-unequal case was handled above. - assert_eq!(src.layout.size, dest_layout.size); - return Ok(*src); + if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() { + let dest_layout = self.layout_of(cast_ty)?; + if dest_layout.size == src.layout.size { + // Thin or fat pointer that just hast the ptr kind of target type changed. + return Ok(*src); + } else { + // Casting the metadata away from a fat ptr. + assert_eq!(src.layout.size, 2 * self.memory.pointer_size()); + assert_eq!(dest_layout.size, self.memory.pointer_size()); + assert!(src.layout.ty.is_unsafe_ptr()); + return match *src { + Immediate::ScalarPair(data, _) => Ok(data.into()), + Immediate::Scalar(..) => bug!( + "{:?} input to a fat-to-thin cast ({:?} -> {:?})", + *src, + src.layout.ty, + cast_ty + ), + }; + } } + // # The remaining source values are scalar. + // For all remaining casts, we either // (a) cast a raw ptr to usize, or // (b) cast from an integer-like (including bool, char, enums). // In both cases we want the bits. let bits = self.force_bits(src.to_scalar()?, src.layout.size)?; - Ok(self.cast_from_int_like(bits, src.layout, dest_layout).into()) + Ok(self.cast_from_scalar(bits, src.layout, cast_ty).into()) } - pub(super) fn cast_from_int_like( + pub(super) fn cast_from_scalar( &self, - v: u128, // raw bits + v: u128, // raw bits (there is no ScalarTy so we separate data+layout) src_layout: TyAndLayout<'tcx>, - dest_layout: TyAndLayout<'tcx>, + cast_ty: Ty<'tcx>, ) -> Scalar { // Let's make sure v is sign-extended *if* it has a signed type. - let signed = src_layout.abi.is_signed(); + let signed = src_layout.abi.is_signed(); // also checks that abi is `Scalar`. let v = if signed { self.sign_extend(v, src_layout) } else { v }; - trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty); + trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty); use rustc_middle::ty::TyKind::*; - match dest_layout.ty.kind { + match cast_ty.kind { Int(_) | Uint(_) | RawPtr(_) => { - let v = self.truncate(v, dest_layout); - Scalar::from_uint(v, dest_layout.size) + let size = match cast_ty.kind { + // FIXME: Isn't there a helper for this? The same pattern occurs below. + Int(t) => { + t.bit_width().map(Size::from_bits).unwrap_or_else(|| self.pointer_size()) + } + Uint(t) => { + t.bit_width().map(Size::from_bits).unwrap_or_else(|| self.pointer_size()) + } + RawPtr(_) => self.pointer_size(), + _ => bug!(), + }; + let v = truncate(v, size); + Scalar::from_uint(v, size) } Float(FloatTy::F32) if signed => Scalar::from_f32(Single::from_i128(v as i128).value), @@ -200,7 +224,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Casts to bool are not permitted by rustc, no need to handle them here. - _ => bug!("invalid int to {:?} cast", dest_layout.ty), + _ => bug!("invalid int to {:?} cast", cast_ty), } } @@ -283,7 +307,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - trace!("Unsizing {:?} into {:?}", src, dest); + trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, dest.layout.ty); match (&src.layout.ty.kind, &dest.layout.ty.kind) { (&ty::Ref(_, s, _), &ty::Ref(_, d, _) | &ty::RawPtr(TypeAndMut { ty: d, .. })) | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: d, .. })) => { diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index bb4c0156c88cf..fd9815975c19f 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -253,9 +253,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), dest)?; } - Cast(kind, ref operand, _) => { + Cast(cast_kind, ref operand, cast_ty) => { let src = self.eval_operand(operand, None)?; - self.cast(src, kind, dest)?; + let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty); + self.cast(src, cast_kind, cast_ty, dest)?; } Discriminant(place) => { From 7a121ad77f0c9b501d127e23af4c53b5a9fd85ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 09:45:14 +0200 Subject: [PATCH 223/695] bootstrap: propagate test-args to miri and clippy test suites --- src/bootstrap/test.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 96196a80be466..ed50f950fb697 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -439,6 +439,8 @@ impl Step for Miri { cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); cargo.env("MIRI_PATH", miri); + cargo.arg("--").args(builder.config.cmd.test_args()); + builder.add_rustc_lib_path(compiler, &mut cargo); if !try_run(builder, &mut cargo.into()) { @@ -545,6 +547,8 @@ impl Step for Clippy { // clippy tests need to find the driver cargo.env("CLIPPY_DRIVER_PATH", clippy); + cargo.arg("--").args(builder.config.cmd.test_args()); + builder.add_rustc_lib_path(compiler, &mut cargo); try_run(builder, &mut cargo.into()); From 806f5815d4528d6a8a4eb5df58151c587a09733c Mon Sep 17 00:00:00 2001 From: Eitan Mosenkis Date: Sun, 24 May 2020 11:59:07 +0300 Subject: [PATCH 224/695] Fix typo in doc comment. call_one_force -> call_once_force --- src/libstd/sync/once.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index a3ee14e85d222..7dc822db3d027 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -272,7 +272,7 @@ impl Once { /// result in an immediate panic. If `f` panics, the `Once` will remain /// in a poison state. If `f` does _not_ panic, the `Once` will no /// longer be in a poison state and all future calls to `call_once` or - /// `call_one_force` will be no-ops. + /// `call_once_force` will be no-ops. /// /// The closure `f` is yielded a [`OnceState`] structure which can be used /// to query the poison status of the `Once`. From 2220eb4d8a06cae7c23b733dee17ebad477cca25 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 24 May 2020 12:52:45 +0200 Subject: [PATCH 225/695] Clean up E0602 explanation --- src/librustc_error_codes/error_codes/E0602.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0602.md b/src/librustc_error_codes/error_codes/E0602.md index ca7138a60cc4e..dcaf251a96b5b 100644 --- a/src/librustc_error_codes/error_codes/E0602.md +++ b/src/librustc_error_codes/error_codes/E0602.md @@ -1,9 +1,9 @@ An unknown lint was used on the command line. -Erroneous example: +Erroneous code example: ```sh -rustc -D bogus omse_file.rs +rustc -D bogus rust_file.rs ``` Maybe you just misspelled the lint name or the lint doesn't exist anymore. From d1f4796845d6a1ce00367a3f8af2bb11790687f9 Mon Sep 17 00:00:00 2001 From: ratijas Date: Sun, 24 May 2020 14:46:50 +0300 Subject: [PATCH 226/695] Use `dyn` trait syntax in more comments and docs Probably missed it out during earlier `dyn` refactoring. --- src/libcore/raw.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index cb0fb8795e581..741a9dc8797be 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -9,15 +9,15 @@ //! Their definition should always match the ABI defined in //! `rustc_middle::ty::layout`. -/// The representation of a trait object like `&SomeTrait`. +/// The representation of a trait object like `&dyn SomeTrait`. /// -/// This struct has the same layout as types like `&SomeTrait` and +/// This struct has the same layout as types like `&dyn SomeTrait` and /// `Box`. /// /// `TraitObject` is guaranteed to match layouts, but it is not the /// type of trait objects (e.g., the fields are not directly accessible -/// on a `&SomeTrait`) nor does it control that layout (changing the -/// definition will not change the layout of a `&SomeTrait`). It is +/// on a `&dyn SomeTrait`) nor does it control that layout (changing the +/// definition will not change the layout of a `&dyn SomeTrait`). It is /// only designed to be used by unsafe code that needs to manipulate /// the low-level details. /// From df2f9a4bd11b2067379c0c97eca3a249fe67fc17 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Sun, 24 May 2020 14:56:57 +0200 Subject: [PATCH 227/695] Use sort_unstable_by in its own docs --- src/libcore/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index b5ce165cb43db..2361749f16645 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1654,7 +1654,7 @@ impl [T] { /// /// ``` /// let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0]; - /// floats.sort_by(|a, b| a.partial_cmp(b).unwrap()); + /// floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); /// assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]); /// ``` /// From b9b1554dac889b7294cd9945691652c632e158bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 15:10:15 +0200 Subject: [PATCH 228/695] Fix unsizing casts --- src/librustc_mir/interpret/cast.rs | 38 ++++++++++++++---------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 18483c70951b4..96b2e92292489 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -25,12 +25,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME: In which cases should we trigger UB when the source is uninit? match cast_kind { Pointer(PointerCast::Unsize) => { - assert_eq!( - cast_ty, dest.layout.ty, - "mismatch of cast type {} and place type {}", - cast_ty, dest.layout.ty - ); - self.unsize_into(src, dest)?; + let cast_ty = self.layout_of(cast_ty)?; + self.unsize_into(src, cast_ty, dest)?; } Misc => { @@ -266,11 +262,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { dest: PlaceTy<'tcx, M::PointerTag>, // The pointee types source_ty: Ty<'tcx>, - dest_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx> { // A -> A conversion let (src_pointee_ty, dest_pointee_ty) = - self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, dest_ty, self.param_env); + self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env); match (&src_pointee_ty.kind, &dest_pointee_ty.kind) { (&ty::Array(_, length), &ty::Slice(_)) => { @@ -298,32 +294,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(val, dest) } - _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty), + _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, cast_ty), } } fn unsize_into( &mut self, src: OpTy<'tcx, M::PointerTag>, + cast_ty: TyAndLayout<'tcx>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, dest.layout.ty); - match (&src.layout.ty.kind, &dest.layout.ty.kind) { - (&ty::Ref(_, s, _), &ty::Ref(_, d, _) | &ty::RawPtr(TypeAndMut { ty: d, .. })) - | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: d, .. })) => { - self.unsize_into_ptr(src, dest, s, d) + trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty); + match (&src.layout.ty.kind, &cast_ty.ty.kind) { + (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. })) + | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => { + self.unsize_into_ptr(src, dest, s, c) } (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => { assert_eq!(def_a, def_b); if def_a.is_box() || def_b.is_box() { if !def_a.is_box() || !def_b.is_box() { - bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout); + bug!("invalid unsizing between {:?} -> {:?}", src.layout.ty, cast_ty.ty); } return self.unsize_into_ptr( src, dest, src.layout.ty.boxed_ty(), - dest.layout.ty.boxed_ty(), + cast_ty.ty.boxed_ty(), ); } @@ -331,15 +328,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Example: `Arc` -> `Arc` // here we need to increase the size of every &T thin ptr field to a fat ptr for i in 0..src.layout.fields.count() { - let dst_field = self.place_field(dest, i)?; - if dst_field.layout.is_zst() { + let cast_ty_field = cast_ty.field(self, i)?; + if cast_ty_field.is_zst() { continue; } let src_field = self.operand_field(src, i)?; - if src_field.layout.ty == dst_field.layout.ty { + let dst_field = self.place_field(dest, i)?; + if src_field.layout.ty == cast_ty_field.ty { self.copy_op(src_field, dst_field)?; } else { - self.unsize_into(src_field, dst_field)?; + self.unsize_into(src_field, cast_ty_field, dst_field)?; } } Ok(()) From 9b87f4009b42802926d166c3dba57d6483fbd325 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 13:59:15 +0200 Subject: [PATCH 229/695] bump Miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 10419b3f2fc62..a6c28f08458e1 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 10419b3f2fc625bb9d746c16d768e433a894484d +Subproject commit a6c28f08458e15cead0e80f3b5b7009786bce4a4 From be2fd61d78b815f2d1cb09b0df5f06d73a089ac8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 24 May 2020 14:26:20 +0100 Subject: [PATCH 230/695] Fix InlineAsmOperand expresions being visited twice during liveness checking --- src/librustc_passes/liveness.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 21512c566e1c5..2d7562ac1c34d 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -1460,26 +1460,20 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { hir::ExprKind::InlineAsm(ref asm) => { for op in asm.operands { match op { - hir::InlineAsmOperand::In { expr, .. } - | hir::InlineAsmOperand::Const { expr, .. } - | hir::InlineAsmOperand::Sym { expr, .. } => this.visit_expr(expr), hir::InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { this.check_place(expr); - this.visit_expr(expr); } } hir::InlineAsmOperand::InOut { expr, .. } => { this.check_place(expr); - this.visit_expr(expr); } - hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { - this.visit_expr(in_expr); + hir::InlineAsmOperand::SplitInOut { out_expr, .. } => { if let Some(out_expr) = out_expr { this.check_place(out_expr); - this.visit_expr(out_expr); } } + _ => {} } } } From 245ebc7210f99528d65e4b46f012dbde2a2f299f Mon Sep 17 00:00:00 2001 From: Rakshith Ravi Date: Sun, 24 May 2020 19:38:54 +0530 Subject: [PATCH 231/695] Removed all instances of const_field. --- src/librustc_codegen_ssa/mir/constant.rs | 16 +++++------- src/librustc_middle/dep_graph/dep_node.rs | 1 - src/librustc_middle/query/mod.rs | 8 ------ src/librustc_mir/const_eval/eval_queries.rs | 2 +- src/librustc_mir/const_eval/mod.rs | 27 --------------------- src/librustc_mir/lib.rs | 4 --- 6 files changed, 7 insertions(+), 51 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index d2629b771c2af..574f91e5b4d81 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -1,6 +1,5 @@ use crate::mir::operand::OperandRef; use crate::traits::*; -use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::layout::HasTyCtxt; @@ -59,17 +58,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { constant .map(|val| { let field_ty = ty.builtin_index().unwrap(); - let fields = match ty.kind { - ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()), - _ => bug!("invalid simd shuffle type: {}", ty), - }; let c = ty::Const::from_value(bx.tcx(), val, ty); - let values: Vec<_> = (0..fields) + let values: Vec<_> = bx + .tcx() + .destructure_const(ty::ParamEnv::reveal_all().and(&c)) + .fields + .into_iter() .map(|field| { - let field = bx.tcx().const_field( - ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))), - ); - if let Some(prim) = field.try_to_scalar() { + if let Some(prim) = field.val.try_to_scalar() { let layout = bx.layout_of(field_ty); let scalar = match layout.abi { Abi::Scalar(ref x) => x, diff --git a/src/librustc_middle/dep_graph/dep_node.rs b/src/librustc_middle/dep_graph/dep_node.rs index 3303790088010..2c0524fa99102 100644 --- a/src/librustc_middle/dep_graph/dep_node.rs +++ b/src/librustc_middle/dep_graph/dep_node.rs @@ -49,7 +49,6 @@ //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -use crate::mir; use crate::mir::interpret::{GlobalId, LitToConstInput}; use crate::traits; use crate::traits::query::{ diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index f7f5c5df8d67b..f04a6f0899a06 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1,5 +1,4 @@ use crate::dep_graph::SerializedDepNodeIndex; -use crate::mir; use crate::mir::interpret::{GlobalId, LitToConstInput}; use crate::traits; use crate::traits::query::{ @@ -553,13 +552,6 @@ rustc_queries! { } } - /// Extracts a field of a (variant of a) const. - query const_field( - key: ty::ParamEnvAnd<'tcx, (&'tcx ty::Const<'tcx>, mir::Field)> - ) -> ConstValue<'tcx> { - desc { "extract field of const" } - } - /// Destructure a constant ADT or array into its variant index and its /// field values. query destructure_const( diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index fd5e0632a2c10..695e0741e3598 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -122,7 +122,7 @@ pub(super) fn op_to_const<'tcx>( } else { // It is guaranteed that any non-slice scalar pair is actually ByRef here. // When we come back from raw const eval, we are always by-ref. The only way our op here is - // by-val is if we are in const_field, i.e., if this is (a field of) something that we + // by-val is if we are in destructure_const, i.e., if this is (a field of) something that we // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or // structs containing such. op.try_as_mplace(ecx) diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/const_eval/mod.rs index 7f557e340bbc8..3539ccf5de038 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/src/librustc_mir/const_eval/mod.rs @@ -5,7 +5,6 @@ use std::convert::TryFrom; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use rustc_target::abi::VariantIdx; use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx}; @@ -19,32 +18,6 @@ pub use eval_queries::*; pub use fn_queries::*; pub use machine::*; -/// Extracts a field of a (variant of a) const. -// this function uses `unwrap` copiously, because an already validated constant must have valid -// fields and can thus never fail outside of compiler bugs -pub(crate) fn const_field<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - variant: Option, - field: mir::Field, - value: &'tcx ty::Const<'tcx>, -) -> ConstValue<'tcx> { - trace!("const_field: {:?}, {:?}", field, value); - let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - // get the operand again - let op = ecx.eval_const_to_op(value, None).unwrap(); - // downcast - let down = match variant { - None => op, - Some(variant) => ecx.operand_downcast(op, variant).unwrap(), - }; - // then project - let field = ecx.operand_field(down, field.index()).unwrap(); - // and finally move back to the const world, always normalizing because - // this is not called for statics. - op_to_const(&ecx, field) -} - pub(crate) fn const_caller_location( tcx: TyCtxt<'tcx>, (file, line, col): (Symbol, u32, u32), diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 785c6c21d7443..928d5bf88f2fc 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -56,10 +56,6 @@ pub fn provide(providers: &mut Providers<'_>) { providers.const_eval_validated = const_eval::const_eval_validated_provider; providers.const_eval_raw = const_eval::const_eval_raw_provider; providers.const_caller_location = const_eval::const_caller_location; - providers.const_field = |tcx, param_env_and_value| { - let (param_env, (value, field)) = param_env_and_value.into_parts(); - const_eval::const_field(tcx, param_env, None, field, value) - }; providers.destructure_const = |tcx, param_env_and_value| { let (param_env, value) = param_env_and_value.into_parts(); const_eval::destructure_const(tcx, param_env, value) From 716acff7b1e68eb10016d167901babdeaa01749a Mon Sep 17 00:00:00 2001 From: Hoe Hao Cheng Date: Sun, 24 May 2020 22:14:06 +0800 Subject: [PATCH 232/695] Remove heterogeneous ordering for SocketAddr --- src/libstd/net/addr.rs | 70 +++++++++--------------------------------- 1 file changed, 15 insertions(+), 55 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 267fb8544c324..6142d5a9e0dab 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -702,26 +702,6 @@ impl PartialOrd for SocketAddrV4 { } } -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl PartialOrd for SocketAddrV4 { - fn partial_cmp(&self, other: &SocketAddr) -> Option { - match other { - SocketAddr::V4(v4) => self.partial_cmp(v4), - SocketAddr::V6(_) => Some(Ordering::Less), - } - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl PartialOrd for SocketAddr { - fn partial_cmp(&self, other: &SocketAddrV4) -> Option { - match self { - SocketAddr::V4(v4) => v4.partial_cmp(other), - SocketAddr::V6(_) => Some(Ordering::Greater), - } - } -} - #[stable(feature = "socketaddr_ordering", since = "1.45.0")] impl PartialOrd for SocketAddrV6 { fn partial_cmp(&self, other: &SocketAddrV6) -> Option { @@ -729,26 +709,6 @@ impl PartialOrd for SocketAddrV6 { } } -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl PartialOrd for SocketAddrV6 { - fn partial_cmp(&self, other: &SocketAddr) -> Option { - match other { - SocketAddr::V4(_) => Some(Ordering::Greater), - SocketAddr::V6(v6) => self.partial_cmp(v6), - } - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl PartialOrd for SocketAddr { - fn partial_cmp(&self, other: &SocketAddrV6) -> Option { - match self { - SocketAddr::V4(_) => Some(Ordering::Less), - SocketAddr::V6(v6) => v6.partial_cmp(other), - } - } -} - #[stable(feature = "socketaddr_ordering", since = "1.45.0")] impl Ord for SocketAddrV4 { fn cmp(&self, other: &SocketAddrV4) -> Ordering { @@ -1213,11 +1173,13 @@ mod tests { let v4_1 = "224.120.45.1:23456".parse::().unwrap(); let v4_2 = "224.210.103.5:12345".parse::().unwrap(); let v4_3 = "224.210.103.5:23456".parse::().unwrap(); - let v6_1 = "[2001:db8:f00::1002]:1234".parse::().unwrap(); - let v6_2 = "[2001:db8:f00::2001]:1234".parse::().unwrap(); - let v6_3 = "[2001:db8:f00::2001]:2345".parse::().unwrap(); + let v6_1 = "[2001:db8:f00::1002]:23456".parse::().unwrap(); + let v6_2 = "[2001:db8:f00::2001]:12345".parse::().unwrap(); + let v6_3 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); // equality + assert_eq!(v4_1, v4_1); + assert_eq!(v6_1, v6_1); assert_eq!(v4_1, SocketAddr::V4(v4_1)); assert_eq!(v6_1, SocketAddr::V6(v6_1)); assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); @@ -1229,22 +1191,20 @@ mod tests { // compare different addresses assert!(v4_1 < v4_2); - assert!(v4_1 < SocketAddr::V4(v4_2)); - assert!(SocketAddr::V4(v4_1) < v4_2); - assert!(SocketAddr::V4(v4_1) < SocketAddr::V4(v4_2)); assert!(v6_1 < v6_2); - assert!(v6_1 < SocketAddr::V6(v6_2)); - assert!(SocketAddr::V6(v6_1) < v6_2); - assert!(SocketAddr::V6(v6_1) < SocketAddr::V6(v6_2)); + assert!(v4_2 > v4_1); + assert!(v6_2 > v6_1); // compare the same address with different ports assert!(v4_2 < v4_3); - assert!(v4_2 < SocketAddr::V4(v4_3)); - assert!(SocketAddr::V4(v4_2) < v4_3); - assert!(SocketAddr::V4(v4_2) < SocketAddr::V4(v4_3)); assert!(v6_2 < v6_3); - assert!(v6_2 < SocketAddr::V6(v6_3)); - assert!(SocketAddr::V6(v6_2) < v6_3); - assert!(SocketAddr::V6(v6_2) < SocketAddr::V6(v6_3)); + assert!(v4_3 > v4_2); + assert!(v6_3 > v6_2); + + // compare different addresses with the same port + assert!(v4_1 < v4_3); + assert!(v6_1 < v6_3); + assert!(v4_1 > v4_3); + assert!(v6_1 > v6_3); } } From d1bc8ada45c5049ff329f02e6de152891f4504e1 Mon Sep 17 00:00:00 2001 From: Hoe Hao Cheng Date: Sun, 24 May 2020 23:04:46 +0800 Subject: [PATCH 233/695] Fix tests --- src/libstd/net/addr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 6142d5a9e0dab..08536de4d55c3 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -1204,7 +1204,7 @@ mod tests { // compare different addresses with the same port assert!(v4_1 < v4_3); assert!(v6_1 < v6_3); - assert!(v4_1 > v4_3); - assert!(v6_1 > v6_3); + assert!(v4_3 > v4_1); + assert!(v6_3 > v6_1); } } From 7b98552cc0f37e886ac3d9b911e0cf1173313c53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 19:17:30 +0200 Subject: [PATCH 234/695] use helper method for determining size of int type --- src/librustc_mir/interpret/cast.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 96b2e92292489..63777b4abde3d 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -3,13 +3,14 @@ use std::convert::TryFrom; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_ast::ast::FloatTy; +use rustc_attr as attr; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::mir::CastKind; use rustc_middle::ty::adjustment::PointerCast; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable}; use rustc_span::symbol::sym; -use rustc_target::abi::{LayoutOf, Size, Variants}; +use rustc_target::abi::{Integer, LayoutOf, Variants}; use super::{truncate, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy}; @@ -195,13 +196,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match cast_ty.kind { Int(_) | Uint(_) | RawPtr(_) => { let size = match cast_ty.kind { - // FIXME: Isn't there a helper for this? The same pattern occurs below. - Int(t) => { - t.bit_width().map(Size::from_bits).unwrap_or_else(|| self.pointer_size()) - } - Uint(t) => { - t.bit_width().map(Size::from_bits).unwrap_or_else(|| self.pointer_size()) - } + Int(t) => Integer::from_attr(self, attr::IntType::SignedInt(t)).size(), + Uint(t) => Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(), RawPtr(_) => self.pointer_size(), _ => bug!(), }; @@ -232,20 +228,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match dest_ty.kind { // float -> uint Uint(t) => { - let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits()); + let size = Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(); // `to_u128` is a saturating cast, which is what we need // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). - let v = f.to_u128(usize::try_from(width).unwrap()).value; + let v = f.to_u128(size.bits_usize()).value; // This should already fit the bit width - Scalar::from_uint(v, Size::from_bits(width)) + Scalar::from_uint(v, size) } // float -> int Int(t) => { - let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits()); + let size = Integer::from_attr(self, attr::IntType::SignedInt(t)).size(); // `to_i128` is a saturating cast, which is what we need // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). - let v = f.to_i128(usize::try_from(width).unwrap()).value; - Scalar::from_int(v, Size::from_bits(width)) + let v = f.to_i128(size.bits_usize()).value; + Scalar::from_int(v, size) } // float -> f32 Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value), From 8b5ba4a3c62e9f663d5f8db1dc4fff245d291c4b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 19:28:44 +0200 Subject: [PATCH 235/695] comment nit --- src/librustc_mir/interpret/cast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 63777b4abde3d..0fd695586eb98 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -189,7 +189,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { cast_ty: Ty<'tcx>, ) -> Scalar { // Let's make sure v is sign-extended *if* it has a signed type. - let signed = src_layout.abi.is_signed(); // also checks that abi is `Scalar`. + let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. let v = if signed { self.sign_extend(v, src_layout) } else { v }; trace!("cast_from_scalar: {}, {} -> {}", v, src_layout.ty, cast_ty); use rustc_middle::ty::TyKind::*; From c3edb15f36653050070b0959682c2d02c2f49bce Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Sat, 23 May 2020 19:29:49 -0400 Subject: [PATCH 236/695] librustc_middle: Rename upvars query to upvars_mentioned As part of supporting RFC 2229, we will be capturing all the Places that were mentioned in the closure. This commit modifies the name of the upvars query to upvars_mentioned. Co-authored-by: Aman Arora Co-authored-by: Chris Pardy --- src/librustc_middle/arena.rs | 2 +- src/librustc_middle/mir/mod.rs | 4 ++-- src/librustc_middle/query/mod.rs | 2 +- src/librustc_middle/ty/print/pretty.rs | 4 ++-- .../borrow_check/diagnostics/mod.rs | 13 ++++++---- src/librustc_mir_build/hair/cx/expr.rs | 2 +- src/librustc_passes/liveness.rs | 10 ++++---- src/librustc_passes/upvars.rs | 4 ++-- .../traits/error_reporting/suggestions.rs | 2 +- src/librustc_typeck/check/closure.rs | 24 ++++++++++--------- src/librustc_typeck/check/upvar.rs | 4 ++-- src/librustc_typeck/expr_use_visitor.rs | 2 +- src/librustc_typeck/mem_categorization.rs | 2 +- 13 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index 2df878c3fb220..9b9207312e8dd 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -61,7 +61,7 @@ macro_rules! arena_types { [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, [few] foreign_module: rustc_middle::middle::cstore::ForeignModule, [few] foreign_modules: Vec, - [] upvars: rustc_data_structures::fx::FxIndexMap, + [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap, [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>, [] attribute: rustc_ast::ast::Attribute, diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 8247338ae0fad..c279213e5bd0e 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -2439,7 +2439,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { }; let mut struct_fmt = fmt.debug_struct(&name); - if let Some(upvars) = tcx.upvars(def_id) { + if let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in upvars.keys().zip(places) { let var_name = tcx.hir().name(var_id); struct_fmt.field(&var_name.as_str(), place); @@ -2458,7 +2458,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let name = format!("[generator@{:?}]", tcx.hir().span(hir_id)); let mut struct_fmt = fmt.debug_struct(&name); - if let Some(upvars) = tcx.upvars(def_id) { + if let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in upvars.keys().zip(places) { let var_name = tcx.hir().name(var_id); struct_fmt.field(&var_name.as_str(), place); diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index f7f5c5df8d67b..2445d484754d0 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1040,7 +1040,7 @@ rustc_queries! { desc { "generating a postorder list of CrateNums" } } - query upvars(_: DefId) -> Option<&'tcx FxIndexMap> { + query upvars_mentioned(_: DefId) -> Option<&'tcx FxIndexMap> { eval_always } query maybe_unused_trait_import(def_id: LocalDefId) -> bool { diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index f4b795e548867..7948fe12724e6 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -611,7 +611,7 @@ pub trait PrettyPrinter<'tcx>: let mut sep = " "; for (&var_id, upvar_ty) in self .tcx() - .upvars(did) + .upvars_mentioned(did) .as_ref() .iter() .flat_map(|v| v.keys()) @@ -660,7 +660,7 @@ pub trait PrettyPrinter<'tcx>: let mut sep = " "; for (&var_id, upvar_ty) in self .tcx() - .upvars(did) + .upvars_mentioned(did) .as_ref() .iter() .flat_map(|v| v.keys()) diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index c218e3906fff2..ca8e54ea28649 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -377,11 +377,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.describe_field_from_ty(&ty, field, variant_index) } ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - // `tcx.upvars(def_id)` returns an `Option`, which is `None` in case + // `tcx.upvars_mentioned(def_id)` returns an `Option`, which is `None` in case // the closure comes from another crate. But in that case we wouldn't // be borrowck'ing it, so we can just unwrap: - let (&var_id, _) = - self.infcx.tcx.upvars(def_id).unwrap().get_index(field.index()).unwrap(); + let (&var_id, _) = self + .infcx + .tcx + .upvars_mentioned(def_id) + .unwrap() + .get_index(field.index()) + .unwrap(); self.infcx.tcx.hir().name(var_id).to_string() } @@ -809,7 +814,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { - for (upvar, place) in self.infcx.tcx.upvars(def_id)?.values().zip(places) { + for (upvar, place) in self.infcx.tcx.upvars_mentioned(def_id)?.values().zip(places) { match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index 99b59d16029ff..114bf5710402f 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -386,7 +386,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( }; let upvars = cx .tcx - .upvars(def_id) + .upvars_mentioned(def_id) .iter() .flat_map(|upvars| upvars.iter()) .zip(substs.upvar_tys()) diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 21512c566e1c5..533d96d28c0b1 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -463,7 +463,7 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); if let Res::Local(var_hir_id) = path.res { - let upvars = ir.tcx.upvars(ir.body_owner); + let upvars = ir.tcx.upvars_mentioned(ir.body_owner); if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hir_id)) { ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); } @@ -481,8 +481,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { // construction site. let mut call_caps = Vec::new(); let closure_def_id = ir.tcx.hir().local_def_id(expr.hir_id); - if let Some(upvars) = ir.tcx.upvars(closure_def_id) { - let parent_upvars = ir.tcx.upvars(ir.body_owner); + if let Some(upvars) = ir.tcx.upvars_mentioned(closure_def_id) { + let parent_upvars = ir.tcx.upvars_mentioned(ir.body_owner); call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| { let has_parent = parent_upvars.map_or(false, |upvars| upvars.contains_key(&var_id)); @@ -1364,7 +1364,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ) -> LiveNode { match path.res { Res::Local(hid) => { - let upvars = self.ir.tcx.upvars(self.ir.body_owner); + let upvars = self.ir.tcx.upvars_mentioned(self.ir.body_owner); if !upvars.map_or(false, |upvars| upvars.contains_key(&hid)) { self.access_var(hir_id, hid, succ, acc, path.span) } else { @@ -1535,7 +1535,7 @@ impl<'tcx> Liveness<'_, 'tcx> { match expr.kind { hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { if let Res::Local(var_hid) = path.res { - let upvars = self.ir.tcx.upvars(self.ir.body_owner); + let upvars = self.ir.tcx.upvars_mentioned(self.ir.body_owner); if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hid)) { // Assignment to an immutable variable or argument: only legal // if there is no later assignment. If this local is actually diff --git a/src/librustc_passes/upvars.rs b/src/librustc_passes/upvars.rs index fb986caa415c9..99b4ef9d12fcd 100644 --- a/src/librustc_passes/upvars.rs +++ b/src/librustc_passes/upvars.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::Span; pub fn provide(providers: &mut Providers<'_>) { - providers.upvars = |tcx, def_id| { + providers.upvars_mentioned = |tcx, def_id| { if !tcx.is_closure(def_id) { return None; } @@ -89,7 +89,7 @@ impl Visitor<'tcx> for CaptureCollector<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(..) = expr.kind { let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id); - if let Some(upvars) = self.tcx.upvars(closure_def_id) { + if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { // Every capture of a closure expression is a local in scope, // that is moved/copied/borrowed into the closure value, and // for this analysis they are like any other access to a local. diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 5c85855535e38..31992f298080e 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1380,7 +1380,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut interior_or_upvar_span = None; let mut interior_extra_info = None; - if let Some(upvars) = self.tcx.upvars(generator_did) { + if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) { interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| { let upvar_ty = tables.node_type(*upvar_id); let upvar_ty = self.resolve_vars_if_possible(&upvar_ty); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index f393121a0adb8..a196081ef7279 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -92,18 +92,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_substs.extend_to(self.tcx, expr_def_id.to_def_id(), |param, _| match param.kind { GenericParamDefKind::Lifetime => span_bug!(expr.span, "closure has lifetime param"), GenericParamDefKind::Type { .. } => if param.index as usize == tupled_upvars_idx { - self.tcx.mk_tup(self.tcx.upvars(expr_def_id).iter().flat_map(|upvars| { - upvars.iter().map(|(&var_hir_id, _)| { - // Create type variables (for now) to represent the transformed - // types of upvars. These will be unified during the upvar - // inference phase (`upvar.rs`). - self.infcx.next_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish upvar inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: self.tcx.hir().span(var_hir_id), + self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map( + |upvars| { + upvars.iter().map(|(&var_hir_id, _)| { + // Create type variables (for now) to represent the transformed + // types of upvars. These will be unified during the upvar + // inference phase (`upvar.rs`). + self.infcx.next_ty_var(TypeVariableOrigin { + // FIXME(eddyb) distinguish upvar inference variables from the rest. + kind: TypeVariableOriginKind::ClosureSynthetic, + span: self.tcx.hir().span(var_hir_id), + }) }) - }) - })) + }, + )) } else { // Create type variables (for now) to represent the various // pieces of information kept in `{Closure,Generic}Substs`. diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 6aa8242193d5f..8707e4fe84a22 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; - if let Some(upvars) = self.tcx.upvars(closure_def_id) { + if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { let mut upvar_list: FxIndexMap = FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default()); for (&var_hir_id, _) in upvars.iter() { @@ -218,7 +218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let closure_def_id = tcx.hir().local_def_id(closure_id); - tcx.upvars(closure_def_id) + tcx.upvars_mentioned(closure_def_id) .iter() .flat_map(|upvars| { upvars.iter().map(|(&var_hir_id, _)| { diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 9ba00faec4978..53973eba22940 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -539,7 +539,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("walk_captures({:?})", closure_expr); let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id); - if let Some(upvars) = self.tcx().upvars(closure_def_id) { + if let Some(upvars) = self.tcx().upvars_mentioned(closure_def_id) { for &var_id in upvars.keys() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_id }, diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index 71f3e2d03c9ff..93d01ccd66f1e 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -159,7 +159,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { infcx, param_env, body_owner, - upvars: infcx.tcx.upvars(body_owner), + upvars: infcx.tcx.upvars_mentioned(body_owner), } } From 14382c6437140bdc2ffaa66edd66f5726a88f156 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 May 2020 16:56:20 -0400 Subject: [PATCH 237/695] Collect tokens for `ast::Expr` --- src/librustc_ast/ast.rs | 3 +- src/librustc_ast/mut_visit.rs | 5 +- src/librustc_ast_lowering/lib.rs | 1 + src/librustc_builtin_macros/asm.rs | 1 + src/librustc_builtin_macros/concat_idents.rs | 1 + src/librustc_builtin_macros/llvm_asm.rs | 1 + src/librustc_expand/base.rs | 1 + src/librustc_expand/build.rs | 10 +++- src/librustc_expand/placeholders.rs | 1 + src/librustc_interface/util.rs | 2 + src/librustc_parse/lib.rs | 8 ++++ src/librustc_parse/parser/diagnostics.rs | 1 + src/librustc_parse/parser/expr.rs | 48 +++++++++++++------ src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 2 + src/test/ui/proc-macro/keep-expr-tokens.rs | 15 ++++++ .../ui/proc-macro/keep-expr-tokens.stderr | 15 ++++++ 16 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/proc-macro/keep-expr-tokens.rs create mode 100644 src/test/ui/proc-macro/keep-expr-tokens.stderr diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 7ff835725073d..30bb5c0bffa6a 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -1006,11 +1006,12 @@ pub struct Expr { pub kind: ExprKind, pub span: Span, pub attrs: AttrVec, + pub tokens: Option, } // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Expr, 96); +rustc_data_structures::static_assert_size!(Expr, 104); impl Expr { /// Returns `true` if this expression would be valid somewhere that expects a value; diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index 2c575c3e28861..7ececb814a6a3 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -1095,7 +1095,10 @@ pub fn noop_visit_anon_const(AnonConst { id, value }: &mut AnonCo vis.visit_expr(value); } -pub fn noop_visit_expr(Expr { kind, id, span, attrs }: &mut Expr, vis: &mut T) { +pub fn noop_visit_expr( + Expr { kind, id, span, attrs, tokens: _ }: &mut Expr, + vis: &mut T, +) { match kind { ExprKind::Box(expr) => vis.visit_expr(expr), ExprKind::Array(exprs) => visit_exprs(exprs, vis), diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 5d98fdeeaf9a5..3aab54ea90949 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1126,6 +1126,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { kind: ExprKind::Path(qself.clone(), path.clone()), span: ty.span, attrs: AttrVec::new(), + tokens: None, }; let ct = self.with_new_scopes(|this| hir::AnonConst { diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index c29739248976c..224b52b239f43 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -519,6 +519,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P( kind: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)), span: self.ident.span, attrs: ast::AttrVec::new(), + tokens: None, })) } diff --git a/src/librustc_builtin_macros/llvm_asm.rs b/src/librustc_builtin_macros/llvm_asm.rs index e12fcd98f9dfe..0f4efc153b941 100644 --- a/src/librustc_builtin_macros/llvm_asm.rs +++ b/src/librustc_builtin_macros/llvm_asm.rs @@ -61,6 +61,7 @@ pub fn expand_llvm_asm<'cx>( kind: ast::ExprKind::LlvmInlineAsm(P(inline_asm)), span: cx.with_def_site_ctxt(sp), attrs: ast::AttrVec::new(), + tokens: None, })) } diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 0137080938fdd..649aac488fcb3 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -594,6 +594,7 @@ impl DummyResult { kind: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(Vec::new()) }, span: sp, attrs: ast::AttrVec::new(), + tokens: None, }) } diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index be2c52a85eb2a..6185e014d3c53 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -70,7 +70,13 @@ impl<'a> ExtCtxt<'a> { pub fn anon_const(&self, span: Span, kind: ast::ExprKind) -> ast::AnonConst { ast::AnonConst { id: ast::DUMMY_NODE_ID, - value: P(ast::Expr { id: ast::DUMMY_NODE_ID, kind, span, attrs: AttrVec::new() }), + value: P(ast::Expr { + id: ast::DUMMY_NODE_ID, + kind, + span, + attrs: AttrVec::new(), + tokens: None, + }), } } @@ -205,7 +211,7 @@ impl<'a> ExtCtxt<'a> { } pub fn expr(&self, span: Span, kind: ast::ExprKind) -> P { - P(ast::Expr { id: ast::DUMMY_NODE_ID, kind, span, attrs: AttrVec::new() }) + P(ast::Expr { id: ast::DUMMY_NODE_ID, kind, span, attrs: AttrVec::new(), tokens: None }) } pub fn expr_path(&self, path: ast::Path) -> P { diff --git a/src/librustc_expand/placeholders.rs b/src/librustc_expand/placeholders.rs index 23f7a5b28fe80..b4ffd714feffa 100644 --- a/src/librustc_expand/placeholders.rs +++ b/src/librustc_expand/placeholders.rs @@ -34,6 +34,7 @@ pub fn placeholder( span, attrs: ast::AttrVec::new(), kind: ast::ExprKind::MacCall(mac_placeholder()), + tokens: None, }) }; let ty = || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span }); diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index a15da94a21561..7eaaff05fb5f0 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -713,6 +713,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { kind: ast::ExprKind::Block(P(b), None), span: rustc_span::DUMMY_SP, attrs: AttrVec::new(), + tokens: None, }); ast::Stmt { @@ -728,6 +729,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: self.resolver.next_node_id(), span: rustc_span::DUMMY_SP, attrs: AttrVec::new(), + tokens: None, }); let loop_stmt = ast::Stmt { diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 0c817a712819f..8ca3f6c5768af 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -272,6 +272,12 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) } Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), + Nonterminal::NtExpr(ref expr) => { + if expr.tokens.is_none() { + debug!("missing tokens for expr {:?}", expr); + } + prepend_attrs(sess, &expr.attrs, expr.tokens.as_ref(), span) + } _ => None, }; @@ -311,6 +317,8 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke "cached tokens found, but they're not \"probably equal\", \ going with stringified version" ); + info!("cached tokens: {:?}", tokens); + info!("reparsed tokens: {:?}", tokens_for_real); } tokens_for_real } diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 93c7faf22a73f..f05d018613852 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -95,6 +95,7 @@ impl RecoverQPath for Expr { kind: ExprKind::Path(qself, path), attrs: AttrVec::new(), id: ast::DUMMY_NODE_ID, + tokens: None, } } } diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index ca497a3b06f4a..e0c372848392c 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -4,6 +4,7 @@ use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; +use log::debug; use rustc_ast::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Lit, UnOp, DUMMY_NODE_ID}; use rustc_ast::ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; use rustc_ast::ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; @@ -431,19 +432,23 @@ impl<'a> Parser<'a> { /// Parses a prefix-unary-operator expr. fn parse_prefix_expr(&mut self, attrs: Option) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(attrs)?; - let lo = self.token.span; - // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() - let (hi, ex) = match self.token.uninterpolate().kind { - token::Not => self.parse_unary_expr(lo, UnOp::Not), // `!expr` - token::Tilde => self.recover_tilde_expr(lo), // `~expr` - token::BinOp(token::Minus) => self.parse_unary_expr(lo, UnOp::Neg), // `-expr` - token::BinOp(token::Star) => self.parse_unary_expr(lo, UnOp::Deref), // `*expr` - token::BinOp(token::And) | token::AndAnd => self.parse_borrow_expr(lo), - token::Ident(..) if self.token.is_keyword(kw::Box) => self.parse_box_expr(lo), - token::Ident(..) if self.is_mistaken_not_ident_negation() => self.recover_not_expr(lo), - _ => return self.parse_dot_or_call_expr(Some(attrs)), - }?; - Ok(self.mk_expr(lo.to(hi), ex, attrs)) + self.maybe_collect_tokens(!attrs.is_empty(), |this| { + let lo = this.token.span; + // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() + let (hi, ex) = match this.token.uninterpolate().kind { + token::Not => this.parse_unary_expr(lo, UnOp::Not), // `!expr` + token::Tilde => this.recover_tilde_expr(lo), // `~expr` + token::BinOp(token::Minus) => this.parse_unary_expr(lo, UnOp::Neg), // `-expr` + token::BinOp(token::Star) => this.parse_unary_expr(lo, UnOp::Deref), // `*expr` + token::BinOp(token::And) | token::AndAnd => this.parse_borrow_expr(lo), + token::Ident(..) if this.token.is_keyword(kw::Box) => this.parse_box_expr(lo), + token::Ident(..) if this.is_mistaken_not_ident_negation() => { + this.recover_not_expr(lo) + } + _ => return this.parse_dot_or_call_expr(Some(attrs)), + }?; + Ok(this.mk_expr(lo.to(hi), ex, attrs)) + }) } fn parse_prefix_expr_common(&mut self, lo: Span) -> PResult<'a, (Span, P)> { @@ -998,6 +1003,21 @@ impl<'a> Parser<'a> { } } + fn maybe_collect_tokens( + &mut self, + has_outer_attrs: bool, + f: impl FnOnce(&mut Self) -> PResult<'a, P>, + ) -> PResult<'a, P> { + if has_outer_attrs { + let (mut expr, tokens) = self.collect_tokens(f)?; + debug!("maybe_collect_tokens: Collected tokens for {:?} (tokens {:?}", expr, tokens); + expr.tokens = Some(tokens); + Ok(expr) + } else { + f(self) + } + } + fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { let lo = self.token.span; match self.parse_opt_lit() { @@ -2169,7 +2189,7 @@ impl<'a> Parser<'a> { } crate fn mk_expr(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P { - P(Expr { kind, span, attrs, id: DUMMY_NODE_ID }) + P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }) } pub(super) fn mk_expr_err(&self, span: Span) -> P { diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index a3d31d257748d..cef600bed5fd7 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -56,6 +56,7 @@ fn expr(kind: ExprKind) -> P { kind, span: DUMMY_SP, attrs: ThinVec::new(), + tokens: None }) } @@ -200,6 +201,7 @@ impl MutVisitor for AddParens { kind: ExprKind::Paren(e), span: DUMMY_SP, attrs: ThinVec::new(), + tokens: None }) }); } diff --git a/src/test/ui/proc-macro/keep-expr-tokens.rs b/src/test/ui/proc-macro/keep-expr-tokens.rs new file mode 100644 index 0000000000000..888785363cfe6 --- /dev/null +++ b/src/test/ui/proc-macro/keep-expr-tokens.rs @@ -0,0 +1,15 @@ +// aux-build:test-macros.rs + +#![feature(stmt_expr_attributes)] +#![feature(proc_macro_hygiene)] + +extern crate test_macros; + +use test_macros::recollect_attr; + +fn main() { + #[test_macros::recollect_attr] + for item in missing_fn() {} //~ ERROR cannot find + + (#[recollect_attr] #[recollect_attr] ((#[recollect_attr] bad))); //~ ERROR cannot +} diff --git a/src/test/ui/proc-macro/keep-expr-tokens.stderr b/src/test/ui/proc-macro/keep-expr-tokens.stderr new file mode 100644 index 0000000000000..2be8c0184da1c --- /dev/null +++ b/src/test/ui/proc-macro/keep-expr-tokens.stderr @@ -0,0 +1,15 @@ +error[E0425]: cannot find function `missing_fn` in this scope + --> $DIR/keep-expr-tokens.rs:12:17 + | +LL | for item in missing_fn() {} + | ^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `bad` in this scope + --> $DIR/keep-expr-tokens.rs:14:62 + | +LL | (#[recollect_attr] #[recollect_attr] ((#[recollect_attr] bad))); + | ^^^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. From cd5f228acd214c0a6555756b060dd0223d31050d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 24 May 2020 16:20:02 -0400 Subject: [PATCH 238/695] Added a codegen test for a recent optimization for overflow-checks=on Closes #58692 --- src/test/codegen/integer-overflow.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/codegen/integer-overflow.rs diff --git a/src/test/codegen/integer-overflow.rs b/src/test/codegen/integer-overflow.rs new file mode 100644 index 0000000000000..183de56db9685 --- /dev/null +++ b/src/test/codegen/integer-overflow.rs @@ -0,0 +1,26 @@ +// no-system-llvm +// compile-flags: -O -C overflow-checks=on + +#![crate_type = "lib"] + + +pub struct S1<'a> { + data: &'a [u8], + position: usize, +} + +// CHECK-LABEL: @slice_no_index_order +#[no_mangle] +pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] { + // CHECK-NOT: slice_index_order_fail + let d = &s.data[s.position..s.position+n]; + s.position += n; + return d; +} + +// CHECK-LABEL: @test_check +#[no_mangle] +pub fn test_check<'a>(s: &'a mut S1, x: usize, y: usize) -> &'a [u8] { + // CHECK: slice_index_order_fail + &s.data[x..y] +} From ebc7eda9e75829305a31a00037056a5365d261fe Mon Sep 17 00:00:00 2001 From: Markus Westerlind Date: Sun, 24 May 2020 15:22:23 +0200 Subject: [PATCH 239/695] perf: Add inline on commonly used methods added in 69464 Reclaims most of the regression in inflate --- .../snapshot_map/mod.rs | 1 + src/librustc_infer/infer/mod.rs | 16 +++++++--- .../infer/region_constraints/mod.rs | 4 +++ src/librustc_infer/infer/type_variable.rs | 31 +++++++++---------- src/librustc_infer/infer/undo_log.rs | 2 ++ src/librustc_infer/traits/project.rs | 2 ++ 6 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index 52865f55f786b..b4cc85293f7c1 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -37,6 +37,7 @@ pub enum UndoLog { } impl SnapshotMap { + #[inline] pub fn with_log(&mut self, undo_log: L2) -> SnapshotMap { SnapshotMap { map: &mut self.map, undo_log, _marker: PhantomData } } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 2cf9dd882e4bb..5dedaced0b112 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -219,18 +219,22 @@ impl<'tcx> InferCtxtInner<'tcx> { } } + #[inline] pub fn region_obligations(&self) -> &[(hir::HirId, RegionObligation<'tcx>)] { &self.region_obligations } + #[inline] pub fn projection_cache(&mut self) -> traits::ProjectionCache<'_, 'tcx> { self.projection_cache.with_log(&mut self.undo_log) } + #[inline] fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> { self.type_variable_storage.with_log(&mut self.undo_log) } + #[inline] fn int_unification_table( &mut self, ) -> ut::UnificationTable< @@ -243,6 +247,7 @@ impl<'tcx> InferCtxtInner<'tcx> { self.int_unification_storage.with_log(&mut self.undo_log) } + #[inline] fn float_unification_table( &mut self, ) -> ut::UnificationTable< @@ -255,6 +260,7 @@ impl<'tcx> InferCtxtInner<'tcx> { self.float_unification_storage.with_log(&mut self.undo_log) } + #[inline] fn const_unification_table( &mut self, ) -> ut::UnificationTable< @@ -267,6 +273,7 @@ impl<'tcx> InferCtxtInner<'tcx> { self.const_unification_storage.with_log(&mut self.undo_log) } + #[inline] pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> { self.region_constraint_storage .as_mut() @@ -1645,14 +1652,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// having to resort to storing full `GenericArg`s in `stalled_on`. #[inline(always)] pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool { - let mut inner = self.inner.borrow_mut(); match infer_var { TyOrConstInferVar::Ty(v) => { use self::type_variable::TypeVariableValue; // If `inlined_probe` returns a `Known` value, it never equals // `ty::Infer(ty::TyVar(v))`. - match inner.type_variables().inlined_probe(v) { + match self.inner.borrow_mut().type_variables().inlined_probe(v) { TypeVariableValue::Unknown { .. } => false, TypeVariableValue::Known { .. } => true, } @@ -1662,7 +1668,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // If `inlined_probe_value` returns a value it's always a // `ty::Int(_)` or `ty::UInt(_)`, which never matches a // `ty::Infer(_)`. - inner.int_unification_table().inlined_probe_value(v).is_some() + self.inner.borrow_mut().int_unification_table().inlined_probe_value(v).is_some() } TyOrConstInferVar::TyFloat(v) => { @@ -1670,7 +1676,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // `ty::Float(_)`, which never matches a `ty::Infer(_)`. // // Not `inlined_probe_value(v)` because this call site is colder. - inner.float_unification_table().probe_value(v).is_some() + self.inner.borrow_mut().float_unification_table().probe_value(v).is_some() } TyOrConstInferVar::Const(v) => { @@ -1678,7 +1684,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // `ty::ConstKind::Infer(ty::InferConst::Var(v))`. // // Not `inlined_probe_value(v)` because this call site is colder. - match inner.const_unification_table().probe_value(v).val { + match self.inner.borrow_mut().const_unification_table().probe_value(v).val { ConstVariableValue::Unknown { .. } => false, ConstVariableValue::Known { .. } => true, } diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 0c9f002a2a21d..095a20105e574 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -68,12 +68,14 @@ pub struct RegionConstraintCollector<'a, 'tcx> { impl std::ops::Deref for RegionConstraintCollector<'_, 'tcx> { type Target = RegionConstraintStorage<'tcx>; + #[inline] fn deref(&self) -> &RegionConstraintStorage<'tcx> { self.storage } } impl std::ops::DerefMut for RegionConstraintCollector<'_, 'tcx> { + #[inline] fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> { self.storage } @@ -345,6 +347,7 @@ impl<'tcx> RegionConstraintStorage<'tcx> { Self::default() } + #[inline] pub(crate) fn with_log<'a>( &'a mut self, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, @@ -796,6 +799,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { .unwrap_or(None) } + #[inline] fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, ty::RegionVid> { ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log) } diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index f68692391a288..53c7dcc637718 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -87,11 +87,7 @@ pub struct TypeVariableStorage<'tcx> { } pub struct TypeVariableTable<'a, 'tcx> { - values: &'a mut sv::SnapshotVecStorage, - - eq_relations: &'a mut ut::UnificationTableStorage>, - - sub_relations: &'a mut ut::UnificationTableStorage, + storage: &'a mut TypeVariableStorage<'tcx>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } @@ -165,12 +161,12 @@ impl<'tcx> TypeVariableStorage<'tcx> { } } + #[inline] pub(crate) fn with_log<'a>( &'a mut self, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, ) -> TypeVariableTable<'a, 'tcx> { - let TypeVariableStorage { values, eq_relations, sub_relations } = self; - TypeVariableTable { values, eq_relations, sub_relations, undo_log } + TypeVariableTable { storage: self, undo_log } } } @@ -180,7 +176,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_diverges(&self, vid: ty::TyVid) -> bool { - self.values.get(vid.index as usize).diverging + self.storage.values.get(vid.index as usize).diverging } /// Returns the origin that was given when `vid` was created. @@ -188,7 +184,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Note that this function does not return care whether /// `vid` has been unified with something else or not. pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.values.get(vid.index as usize).origin + &self.storage.values.get(vid.index as usize).origin } /// Records that `a == b`, depending on `dir`. @@ -265,7 +261,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Returns the number of type variables created thus far. pub fn num_vars(&self) -> usize { - self.values.len() + self.storage.values.len() } /// Returns the "root" variable of `vid` in the `eq_relations` @@ -319,18 +315,21 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { } } + #[inline] fn values( &mut self, ) -> sv::SnapshotVec, &mut InferCtxtUndoLogs<'tcx>> { - self.values.with_log(self.undo_log) + self.storage.values.with_log(self.undo_log) } + #[inline] fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> { - self.eq_relations.with_log(self.undo_log) + self.storage.eq_relations.with_log(self.undo_log) } + #[inline] fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> { - self.sub_relations.with_log(self.undo_log) + self.storage.sub_relations.with_log(self.undo_log) } /// Returns a range of the type variables created during the snapshot. @@ -342,7 +341,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { ( range.start..range.end, (range.start.index..range.end.index) - .map(|index| self.values.get(index as usize).origin) + .map(|index| self.storage.values.get(index as usize).origin) .collect(), ) } @@ -378,7 +377,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { // quick check to see if this variable was // created since the snapshot started or not. let mut eq_relations = ut::UnificationTable::with_log( - &mut *self.eq_relations, + &mut self.storage.eq_relations, &mut *self.undo_log, ); let escaping_type = match eq_relations.probe_value(vid) { @@ -400,7 +399,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Returns indices of all variables that are not yet /// instantiated. pub fn unsolved_variables(&mut self) -> Vec { - (0..self.values.len()) + (0..self.storage.values.len()) .filter_map(|i| { let vid = ty::TyVid { index: i as u32 }; match self.probe(vid) { diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs index 56cb182dbf0f9..e7f1869955d20 100644 --- a/src/librustc_infer/infer/undo_log.rs +++ b/src/librustc_infer/infer/undo_log.rs @@ -100,10 +100,12 @@ impl<'tcx, T> UndoLogs for InferCtxtUndoLogs<'tcx> where UndoLog<'tcx>: From, { + #[inline] fn num_open_snapshots(&self) -> usize { self.num_open_snapshots } + #[inline] fn push(&mut self, undo: T) { if self.in_snapshot() { self.logs.push(undo.into()) diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index f0d21a7d022da..65284bcee912c 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -95,6 +95,7 @@ pub enum ProjectionCacheEntry<'tcx> { } impl<'tcx> ProjectionCacheStorage<'tcx> { + #[inline] pub(crate) fn with_log<'a>( &'a mut self, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, @@ -104,6 +105,7 @@ impl<'tcx> ProjectionCacheStorage<'tcx> { } impl<'tcx> ProjectionCache<'_, 'tcx> { + #[inline] fn map( &mut self, ) -> SnapshotMapRef< From 698df11af56f1326bb6509e8c1329b463b0afc9c Mon Sep 17 00:00:00 2001 From: Andrew Lilley Brinker Date: Sun, 24 May 2020 15:30:48 -0700 Subject: [PATCH 240/695] First draft documenting Debug stability. Debug implementations of std types aren't stable, and neither are derived Debug implementations for any types, including user-defined types. This commit adds a section to the Debug documentatio noting this stability status. --- src/libcore/fmt/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 95411b525d0db..3d90fe1fa2f21 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -441,6 +441,13 @@ impl Display for Arguments<'_> { /// `enum`s, it will use the name of the variant and, if applicable, `(`, then the /// `Debug` values of the fields, then `)`. /// +/// # Stability +/// +/// Derived `Debug` formats are not stable, and so may change with future Rust +/// versions. Additionally, `Debug` implementations of types provided by the +/// standard library (`libstd`, `libcore`, `liballoc`, etc.) are not stable, and +/// may also change with future Rust versions. +/// /// # Examples /// /// Deriving an implementation: From 3fcb0f4bfaea1de5fa86a464a7a9d6a0fb30cbca Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 15:07:55 +0900 Subject: [PATCH 241/695] Enable `glacier` command via triagebot --- triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index f12d516376322..e43cff5538659 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -10,6 +10,8 @@ allow-unauthenticated = [ [assign] +[glacier] + [ping.icebreakers-llvm] alias = ["llvm", "llvms"] message = """\ From d59fa081ec272573ef560c4ea914466fce74db3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 08:52:16 +0200 Subject: [PATCH 242/695] fix ICE when debug-printing MIR --- src/librustc_middle/ty/print/pretty.rs | 30 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index f03d91aa64b78..a47addf18044c 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -1,5 +1,7 @@ use crate::middle::cstore::{ExternCrate, ExternCrateSource}; -use crate::mir::interpret::{sign_extend, truncate, AllocId, ConstValue, Pointer, Scalar}; +use crate::mir::interpret::{ + sign_extend, truncate, AllocId, ConstValue, GlobalAlloc, Pointer, Scalar, +}; use crate::ty::layout::IntegerExt; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; @@ -951,15 +953,20 @@ pub trait PrettyPrinter<'tcx>: }, _, ), - ) => { - let byte_str = self - .tcx() - .global_alloc(ptr.alloc_id) - .unwrap_memory() - .get_bytes(&self.tcx(), ptr, Size::from_bytes(*data)) - .unwrap(); - p!(pretty_print_byte_str(byte_str)); - } + ) => match self.tcx().get_global_alloc(ptr.alloc_id) { + Some(GlobalAlloc::Memory(alloc)) => { + if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), ptr, Size::from_bytes(*data)) + { + p!(pretty_print_byte_str(byte_str)) + } else { + p!(write("")) + } + } + // FIXME: for statics and functions, we could in principle print more detail. + Some(GlobalAlloc::Static(def_id)) => p!(write("", def_id)), + Some(GlobalAlloc::Function(_)) => p!(write("")), + None => p!(write("")), + }, // Bool (Scalar::Raw { data: 0, .. }, ty::Bool) => p!(write("false")), (Scalar::Raw { data: 1, .. }, ty::Bool) => p!(write("true")), @@ -1018,6 +1025,9 @@ pub trait PrettyPrinter<'tcx>: )?; } (Scalar::Ptr(ptr), ty::FnPtr(_)) => { + // FIXME: this can ICE when the ptr is dangling or points to a non-function. + // We should probably have a helper method to share code with the "Byte strings" + // printing above (which also has to handle pointers to all sorts of things). let instance = self.tcx().global_alloc(ptr.alloc_id).unwrap_fn(); self = self.typed_value( |this| this.print_value_path(instance.def_id(), instance.substs), From 4e4b1edda850157ea2e65b97ed77b2bef934cb85 Mon Sep 17 00:00:00 2001 From: Ross MacArthur Date: Mon, 25 May 2020 09:23:00 +0200 Subject: [PATCH 243/695] Add test for old compiler ICE when using `Borrow` --- .../ui/issues/issue-50687-ice-on-borrow.rs | 41 +++++++++++++++++++ .../issues/issue-50687-ice-on-borrow.stderr | 16 ++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/test/ui/issues/issue-50687-ice-on-borrow.rs create mode 100644 src/test/ui/issues/issue-50687-ice-on-borrow.stderr diff --git a/src/test/ui/issues/issue-50687-ice-on-borrow.rs b/src/test/ui/issues/issue-50687-ice-on-borrow.rs new file mode 100644 index 0000000000000..7a8a12c2a93af --- /dev/null +++ b/src/test/ui/issues/issue-50687-ice-on-borrow.rs @@ -0,0 +1,41 @@ +// This previously caused an ICE at: +// librustc/traits/structural_impls.rs:180: impossible case reached + +#![no_main] + +use std::borrow::Borrow; +use std::io; +use std::io::Write; + +trait Constraint {} + +struct Container { + t: T, +} + +struct Borrowed; +struct Owned; + +impl<'a, T> Write for &'a Container +where + T: Constraint, + &'a T: Write, +{ + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Borrow for Owned { + fn borrow(&self) -> &Borrowed { + &Borrowed + } +} + +fn func(owned: Owned) { + let _: () = Borrow::borrow(&owned); //~ ERROR mismatched types +} diff --git a/src/test/ui/issues/issue-50687-ice-on-borrow.stderr b/src/test/ui/issues/issue-50687-ice-on-borrow.stderr new file mode 100644 index 0000000000000..f6adfc87dad33 --- /dev/null +++ b/src/test/ui/issues/issue-50687-ice-on-borrow.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/issue-50687-ice-on-borrow.rs:40:17 + | +LL | let _: () = Borrow::borrow(&owned); + | -- ^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | expected `()`, found reference + | | help: consider dereferencing the borrow: `*Borrow::borrow(&owned)` + | expected due to this + | + = note: expected unit type `()` + found reference `&_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From b27e649537770ba6631f3347974e3ae7e082adfe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 May 2020 16:17:07 +0200 Subject: [PATCH 244/695] add a lint against references to packed fields --- .../transform/check_packed_ref.rs | 66 +++++++++++++++++++ src/librustc_mir/transform/mod.rs | 6 +- src/librustc_session/lint/builtin.rs | 9 ++- src/test/ui/lint/packed_reference.rs | 25 +++++++ src/test/ui/lint/packed_reference.stderr | 23 +++++++ 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/librustc_mir/transform/check_packed_ref.rs create mode 100644 src/test/ui/lint/packed_reference.rs create mode 100644 src/test/ui/lint/packed_reference.stderr diff --git a/src/librustc_mir/transform/check_packed_ref.rs b/src/librustc_mir/transform/check_packed_ref.rs new file mode 100644 index 0000000000000..9e07a4599f686 --- /dev/null +++ b/src/librustc_mir/transform/check_packed_ref.rs @@ -0,0 +1,66 @@ +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_session::lint::builtin::PACKED_REFERENCES; + +use crate::transform::{MirPass, MirSource}; +use crate::util; + +pub struct CheckPackedRef; + +impl<'tcx> MirPass<'tcx> for CheckPackedRef { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + let param_env = tcx.param_env(src.instance.def_id()); + let source_info = SourceInfo::outermost(body.span); + let mut checker = PackedRefChecker { body, tcx, param_env, source_info }; + checker.visit_body(&body); + } +} + +struct PackedRefChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + source_info: SourceInfo, +} + +impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + // Make sure we know where in the MIR we are. + self.source_info = terminator.source_info; + self.super_terminator(terminator, location); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + // Make sure we know where in the MIR we are. + self.source_info = statement.source_info; + self.super_statement(statement, location); + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + if context.is_borrow() { + if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { + let source_info = self.source_info; + let lint_root = self.body.source_scopes[source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + self.tcx.struct_span_lint_hir( + PACKED_REFERENCES, + lint_root, + source_info.span, + |lint| { + lint.build(&format!("reference to packed field is not allowed",)) + .note( + "fields of packed structs might be misaligned, and creating \ + a misaligned reference is undefined behavior (even if that \ + reference is never dereferenced)", + ) + .emit() + }, + ); + } + } + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 0551ed5a15ddb..7d2f890362480 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -17,6 +17,7 @@ pub mod add_call_guards; pub mod add_moves_for_packed_drops; pub mod add_retag; pub mod check_consts; +pub mod check_packed_ref; pub mod check_unsafety; pub mod cleanup_post_borrowck; pub mod const_prop; @@ -211,10 +212,11 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs { validator.qualifs_in_return_place() } +/// Make MIR ready for const evaluation. This is run on all MIR, not just on consts! fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> Steal> { let def_id = def_id.expect_local(); - // Unsafety check uses the raw mir, so make sure it is run + // Unsafety check uses the raw mir, so make sure it is run. let _ = tcx.unsafety_check_result(def_id); let mut body = tcx.mir_built(def_id).steal(); @@ -230,6 +232,8 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> Steal> { None, MirPhase::Const, &[&[ + // MIR-level lints. + &check_packed_ref::CheckPackedRef, // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 3d03e46683ed5..0753e9e4b7325 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -216,10 +216,16 @@ declare_lint! { "lints that have been renamed or removed" } +declare_lint! { + pub PACKED_REFERENCES, + Allow, + "detects unaligned references to fields of packed structs", +} + declare_lint! { pub SAFE_PACKED_BORROWS, Warn, - "safe borrows of fields of packed structs were was erroneously allowed", + "safe borrows of fields of packed structs were erroneously allowed", @future_incompatible = FutureIncompatibleInfo { reference: "issue #46043 ", edition: None, @@ -545,6 +551,7 @@ declare_lint_pass! { INVALID_TYPE_PARAM_DEFAULT, CONST_ERR, RENAMED_AND_REMOVED_LINTS, + PACKED_REFERENCES, SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, MISSING_FRAGMENT_SPECIFIER, diff --git a/src/test/ui/lint/packed_reference.rs b/src/test/ui/lint/packed_reference.rs new file mode 100644 index 0000000000000..d588ffd212006 --- /dev/null +++ b/src/test/ui/lint/packed_reference.rs @@ -0,0 +1,25 @@ +#![deny(packed_references)] + +#[repr(packed)] +pub struct Good { + data: &'static u32, + data2: [&'static u32; 2], + aligned: [u8; 32], +} + +#[repr(packed)] +pub struct JustArray { + array: [u32], +} + +fn main() { + unsafe { + let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; + + let _ = &good.data; //~ ERROR reference to packed field + let _ = &good.data2[0]; //~ ERROR reference to packed field + let _ = &*good.data; // ok, behind a pointer + let _ = &good.aligned; // ok, has align 1 + let _ = &good.aligned[2]; // ok, has align 1 + } +} diff --git a/src/test/ui/lint/packed_reference.stderr b/src/test/ui/lint/packed_reference.stderr new file mode 100644 index 0000000000000..094fb4f34d329 --- /dev/null +++ b/src/test/ui/lint/packed_reference.stderr @@ -0,0 +1,23 @@ +error: reference to packed field is not allowed + --> $DIR/packed_reference.rs:19:17 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/packed_reference.rs:1:9 + | +LL | #![deny(packed_references)] + | ^^^^^^^^^^^^^^^^^ + = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is not allowed + --> $DIR/packed_reference.rs:20:17 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | + = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: aborting due to 2 previous errors + From c79535eab9500b87ab62f9e077db3953aa06b486 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 May 2020 16:29:27 +0200 Subject: [PATCH 245/695] remove some unused types from the tests --- src/test/ui/issues/issue-27060-rpass.rs | 11 +---------- src/test/ui/issues/issue-27060.rs | 5 ----- src/test/ui/issues/issue-27060.stderr | 6 +++--- src/test/ui/lint/packed_reference.rs | 5 ----- src/test/ui/lint/packed_reference.stderr | 4 ++-- 5 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/test/ui/issues/issue-27060-rpass.rs b/src/test/ui/issues/issue-27060-rpass.rs index b6ffc3ecb5133..b20d614b3036b 100644 --- a/src/test/ui/issues/issue-27060-rpass.rs +++ b/src/test/ui/issues/issue-27060-rpass.rs @@ -7,19 +7,10 @@ pub struct Good { aligned: [u8; 32], } -#[repr(packed)] -pub struct JustArray { - array: [u32] -} - // kill this test when that turns to a hard error #[allow(safe_packed_borrows)] fn main() { - let good = Good { - data: &0, - data2: [&0, &0], - aligned: [0; 32] - }; + let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; unsafe { let _ = &good.data; // ok diff --git a/src/test/ui/issues/issue-27060.rs b/src/test/ui/issues/issue-27060.rs index 4caad03a36151..78f2022ed38df 100644 --- a/src/test/ui/issues/issue-27060.rs +++ b/src/test/ui/issues/issue-27060.rs @@ -5,11 +5,6 @@ pub struct Good { aligned: [u8; 32], } -#[repr(packed)] -pub struct JustArray { - array: [u32] -} - #[deny(safe_packed_borrows)] fn main() { let good = Good { diff --git a/src/test/ui/issues/issue-27060.stderr b/src/test/ui/issues/issue-27060.stderr index 6bf6348631a70..d14ae4d41d5c5 100644 --- a/src/test/ui/issues/issue-27060.stderr +++ b/src/test/ui/issues/issue-27060.stderr @@ -1,11 +1,11 @@ error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) - --> $DIR/issue-27060.rs:26:13 + --> $DIR/issue-27060.rs:21:13 | LL | let _ = &good.data; | ^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-27060.rs:13:8 + --> $DIR/issue-27060.rs:8:8 | LL | #[deny(safe_packed_borrows)] | ^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | #[deny(safe_packed_borrows)] = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) - --> $DIR/issue-27060.rs:28:13 + --> $DIR/issue-27060.rs:23:13 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/packed_reference.rs b/src/test/ui/lint/packed_reference.rs index d588ffd212006..c684fd62ee345 100644 --- a/src/test/ui/lint/packed_reference.rs +++ b/src/test/ui/lint/packed_reference.rs @@ -7,11 +7,6 @@ pub struct Good { aligned: [u8; 32], } -#[repr(packed)] -pub struct JustArray { - array: [u32], -} - fn main() { unsafe { let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; diff --git a/src/test/ui/lint/packed_reference.stderr b/src/test/ui/lint/packed_reference.stderr index 094fb4f34d329..428f4b66944ec 100644 --- a/src/test/ui/lint/packed_reference.stderr +++ b/src/test/ui/lint/packed_reference.stderr @@ -1,5 +1,5 @@ error: reference to packed field is not allowed - --> $DIR/packed_reference.rs:19:17 + --> $DIR/packed_reference.rs:14:17 | LL | let _ = &good.data; | ^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(packed_references)] = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is not allowed - --> $DIR/packed_reference.rs:20:17 + --> $DIR/packed_reference.rs:15:17 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ From 061773fd2b7fd40ba7c368de50878539d30f7bb1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 11:15:38 +0200 Subject: [PATCH 246/695] more test ref-to-packed tests --- src/test/ui/lint/packed_reference.rs | 2 ++ src/test/ui/lint/packed_reference.stderr | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/test/ui/lint/packed_reference.rs b/src/test/ui/lint/packed_reference.rs index c684fd62ee345..349421084682b 100644 --- a/src/test/ui/lint/packed_reference.rs +++ b/src/test/ui/lint/packed_reference.rs @@ -12,6 +12,8 @@ fn main() { let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; let _ = &good.data; //~ ERROR reference to packed field + let _ = &good.data as *const _; //~ ERROR reference to packed field + let _: *const _ = &good.data; //~ ERROR reference to packed field let _ = &good.data2[0]; //~ ERROR reference to packed field let _ = &*good.data; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 diff --git a/src/test/ui/lint/packed_reference.stderr b/src/test/ui/lint/packed_reference.stderr index 428f4b66944ec..51158a84175dc 100644 --- a/src/test/ui/lint/packed_reference.stderr +++ b/src/test/ui/lint/packed_reference.stderr @@ -14,10 +14,26 @@ LL | #![deny(packed_references)] error: reference to packed field is not allowed --> $DIR/packed_reference.rs:15:17 | +LL | let _ = &good.data as *const _; + | ^^^^^^^^^^ + | + = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is not allowed + --> $DIR/packed_reference.rs:16:27 + | +LL | let _: *const _ = &good.data; + | ^^^^^^^^^^ + | + = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is not allowed + --> $DIR/packed_reference.rs:17:17 + | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors From ee6e705d91a7b19aa2d029b21396c70e2129f741 Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Sun, 24 May 2020 13:11:12 +0100 Subject: [PATCH 247/695] Fix UB in Arc Use raw pointers to avoid making any assertions about the data field. --- src/liballoc/sync.rs | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 2bcf763354247..385506dc7a13d 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -866,12 +866,10 @@ impl Arc { unsafe fn drop_slow(&mut self) { // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). - ptr::drop_in_place(&mut self.ptr.as_mut().data); + ptr::drop_in_place(Self::get_mut_unchecked(self)); - if self.inner().weak.fetch_sub(1, Release) == 1 { - acquire!(self.inner().weak); - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) - } + // Drop the weak ref collectively held by all strong references + drop(Weak { ptr: self.ptr }); } #[inline] @@ -1201,7 +1199,7 @@ impl Arc { // As with `get_mut()`, the unsafety is ok because our reference was // either unique to begin with, or became one upon cloning the contents. - unsafe { &mut this.ptr.as_mut().data } + unsafe { Self::get_mut_unchecked(this) } } } @@ -1277,7 +1275,9 @@ impl Arc { #[inline] #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - &mut this.ptr.as_mut().data + // We are careful to *not* create a reference covering the "count" fields, as + // this would alias with concurrent access to the reference counts (e.g. by `Weak`). + &mut (*this.ptr.as_ptr()).data } /// Determine whether this is the unique reference (including weak refs) to @@ -1568,6 +1568,13 @@ impl Weak { } } +/// Helper type to allow accessing the reference counts without +/// making any assertions about the data field. +struct WeakInner<'a> { + weak: &'a atomic::AtomicUsize, + strong: &'a atomic::AtomicUsize, +} + impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying /// dropping of the inner value if successful. @@ -1673,8 +1680,18 @@ impl Weak { /// Returns `None` when the pointer is dangling and there is no allocated `ArcInner`, /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] - fn inner(&self) -> Option<&ArcInner> { - if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) } + fn inner(&self) -> Option> { + if is_dangling(self.ptr) { + None + } else { + // We are careful to *not* create a reference covering the "data" field, as + // the field may be mutated concurrently (for example, if the last `Arc` + // is dropped, the data field will be dropped in-place). + Some(unsafe { + let ptr = self.ptr.as_ptr(); + WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } + }) + } } /// Returns `true` if the two `Weak`s point to the same allocation (similar to From 632f3de12bc71167485253510b2e1644b25302ce Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 25 May 2020 13:03:38 +0200 Subject: [PATCH 248/695] Clean up E0608 explanation --- src/librustc_error_codes/error_codes/E0608.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0608.md b/src/librustc_error_codes/error_codes/E0608.md index 598f1e655e964..d0ebc3a26f082 100644 --- a/src/librustc_error_codes/error_codes/E0608.md +++ b/src/librustc_error_codes/error_codes/E0608.md @@ -1,4 +1,4 @@ -An attempt to index into a type which doesn't implement the `std::ops::Index` +An attempt to use index on a type which doesn't implement the `std::ops::Index` trait was performed. Erroneous code example: From 68bab3e56e7df618c093f5b93901f5319ef65997 Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Sat, 23 May 2020 04:41:24 +0900 Subject: [PATCH 249/695] Add total_cmp to f32 and f64, plus tests --- src/libcore/num/f32.rs | 73 +++++++++++++++++++++ src/libcore/num/f64.rs | 73 +++++++++++++++++++++ src/libstd/f32.rs | 143 +++++++++++++++++++++++++++++++++++++++++ src/libstd/f64.rs | 143 +++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + 5 files changed, 433 insertions(+) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 434569020d2a8..47f489c40abb1 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -810,4 +810,77 @@ impl f32 { pub fn from_ne_bytes(bytes: [u8; 4]) -> Self { Self::from_bits(u32::from_ne_bytes(bytes)) } + + /// Returns an ordering between self and other values. + /// Unlike the standard partial comparison between floating point numbers, + /// this comparison always produces an ordering in accordance to + /// the totalOrder predicate as defined in IEEE 754 (2008 revision) + /// floating point standard. The values are ordered in following order: + /// - Negative quiet NaN + /// - Negative signaling NaN + /// - Negative infinity + /// - Negative numbers + /// - Negative subnormal numbers + /// - Negative zero + /// - Positive zero + /// - Positive subnormal numbers + /// - Positive numbers + /// - Positive infinity + /// - Positive signaling NaN + /// - Positive quiet NaN + /// + /// # Example + /// ``` + /// #![feature(total_cmp)] + /// struct GoodBoy { + /// name: String, + /// weight: f32, + /// } + /// + /// let mut bois = vec![ + /// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 }, + /// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 }, + /// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 }, + /// GoodBoy { name: "Chonk".to_owned(), weight: f32::INFINITY }, + /// GoodBoy { name: "Abs. Unit".to_owned(), weight: f32::NAN }, + /// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 }, + /// ]; + /// + /// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight)); + /// # assert!(bois.into_iter().map(|b| b.weight) + /// # .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter()) + /// # .all(|(a, b)| a.to_bits() == b.to_bits())) + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "total_cmp", issue = "none")] + #[inline] + pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { + let mut left = self.to_bits() as i32; + let mut right = other.to_bits() as i32; + + // In case of negatives, flip all the bits expect the sign + // to achieve a similar layout as two's complement integers + // + // Why does this work? IEEE 754 floats consist of three fields: + // Sign bit, exponent and mantissa. The set of exponent and mantissa + // fields as a whole have the property that their bitwise order is + // equal to the numeric magnitude where the magnitude is defined. + // The magnitude is not normally defined on NaN values, but + // IEEE 754 totalOrder defines the NaN values also to follow the + // bitwise order. This leads to order explained in the doc comment. + // However, the representation of magnitude is the same for negative + // and positive numbers – only the sign bit is different. + // To easily compare the floats as signed integers, we need to + // flip the exponent and mantissa bits in case of negative numbers. + // We effectively convert the numbers to "two's complement" form. + if left < 0 { + // i32::MAX corresponds the bit pattern of "all ones expect for the sign bit" + left ^= i32::MAX + }; + if right < 0 { + right ^= i32::MAX + }; + + left.cmp(&right) + } } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 6476ddb4541ff..9c02180838014 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -824,4 +824,77 @@ impl f64 { pub fn from_ne_bytes(bytes: [u8; 8]) -> Self { Self::from_bits(u64::from_ne_bytes(bytes)) } + + /// Returns an ordering between self and other values. + /// Unlike the standard partial comparison between floating point numbers, + /// this comparison always produces an ordering in accordance to + /// the totalOrder predicate as defined in IEEE 754 (2008 revision) + /// floating point standard. The values are ordered in following order: + /// - Negative quiet NaN + /// - Negative signaling NaN + /// - Negative infinity + /// - Negative numbers + /// - Negative subnormal numbers + /// - Negative zero + /// - Positive zero + /// - Positive subnormal numbers + /// - Positive numbers + /// - Positive infinity + /// - Positive signaling NaN + /// - Positive quiet NaN + /// + /// # Example + /// ``` + /// #![feature(total_cmp)] + /// struct GoodBoy { + /// name: String, + /// weight: f64, + /// } + /// + /// let mut bois = vec![ + /// GoodBoy { name: "Pucci".to_owned(), weight: 0.1 }, + /// GoodBoy { name: "Woofer".to_owned(), weight: 99.0 }, + /// GoodBoy { name: "Yapper".to_owned(), weight: 10.0 }, + /// GoodBoy { name: "Chonk".to_owned(), weight: f64::INFINITY }, + /// GoodBoy { name: "Abs. Unit".to_owned(), weight: f64::NAN }, + /// GoodBoy { name: "Floaty".to_owned(), weight: -5.0 }, + /// ]; + /// + /// bois.sort_by(|a, b| a.weight.total_cmp(&b.weight)); + /// # assert!(bois.into_iter().map(|b| b.weight) + /// # .zip([-5.0, 0.1, 10.0, 99.0, f64::INFINITY, f64::NAN].iter()) + /// # .all(|(a, b)| a.to_bits() == b.to_bits())) + /// ``` + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "total_cmp", issue = "none")] + #[inline] + pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { + let mut left = self.to_bits() as i64; + let mut right = other.to_bits() as i64; + + // In case of negatives, flip all the bits expect the sign + // to achieve a similar layout as two's complement integers + // + // Why does this work? IEEE 754 floats consist of three fields: + // Sign bit, exponent and mantissa. The set of exponent and mantissa + // fields as a whole have the property that their bitwise order is + // equal to the numeric magnitude where the magnitude is defined. + // The magnitude is not normally defined on NaN values, but + // IEEE 754 totalOrder defines the NaN values also to follow the + // bitwise order. This leads to order explained in the doc comment. + // However, the representation of magnitude is the same for negative + // and positive numbers – only the sign bit is different. + // To easily compare the floats as signed integers, we need to + // flip the exponent and mantissa bits in case of negative numbers. + // We effectively convert the numbers to "two's complement" form. + if left < 0 { + // i64::MAX corresponds the bit pattern of "all ones expect for the sign bit" + left ^= i64::MAX + }; + if right < 0 { + right ^= i64::MAX + }; + + left.cmp(&right) + } } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 8e743ace99bfb..c5d8bb4fcf243 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1531,4 +1531,147 @@ mod tests { fn test_clamp_max_is_nan() { let _ = 1.0f32.clamp(3.0, NAN); } + + #[test] + fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u32 { + 1 << (f32::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f32 { + f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0) + } + + fn max_subnorm() -> f32 { + f32::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f32 { + f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f32 { + f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); + } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index fe64d27b1efc8..eae8a04bfc637 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1554,4 +1554,147 @@ mod tests { fn test_clamp_max_is_nan() { let _ = 1.0f64.clamp(3.0, NAN); } + + #[test] + fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u64 { + 1 << (f64::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f64 { + f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0) + } + + fn max_subnorm() -> f64 { + f64::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f64 { + f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f64 { + f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ac07af5e278fb..468ac7bb5e873 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -308,6 +308,7 @@ #![feature(test)] #![feature(thread_local)] #![feature(toowned_clone_into)] +#![feature(total_cmp)] #![feature(trace_macros)] #![feature(track_caller)] #![feature(try_reserve)] From d959a8f91d9945302f58a8f79613e75060c6b77d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 15:32:46 +0200 Subject: [PATCH 250/695] rename lint --- .../transform/check_packed_ref.rs | 8 ++-- src/librustc_session/lint/builtin.rs | 4 +- src/test/ui/lint/packed_reference.stderr | 39 ------------------- ...d_reference.rs => unaligned_references.rs} | 2 +- src/test/ui/lint/unaligned_references.stderr | 39 +++++++++++++++++++ 5 files changed, 46 insertions(+), 46 deletions(-) delete mode 100644 src/test/ui/lint/packed_reference.stderr rename src/test/ui/lint/{packed_reference.rs => unaligned_references.rs} (95%) create mode 100644 src/test/ui/lint/unaligned_references.stderr diff --git a/src/librustc_mir/transform/check_packed_ref.rs b/src/librustc_mir/transform/check_packed_ref.rs index 9e07a4599f686..faad1a72327f4 100644 --- a/src/librustc_mir/transform/check_packed_ref.rs +++ b/src/librustc_mir/transform/check_packed_ref.rs @@ -1,7 +1,7 @@ use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::PACKED_REFERENCES; +use rustc_session::lint::builtin::UNALIGNED_REFERENCES; use crate::transform::{MirPass, MirSource}; use crate::util; @@ -47,13 +47,13 @@ impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> { .assert_crate_local() .lint_root; self.tcx.struct_span_lint_hir( - PACKED_REFERENCES, + UNALIGNED_REFERENCES, lint_root, source_info.span, |lint| { - lint.build(&format!("reference to packed field is not allowed",)) + lint.build(&format!("reference to packed field is unaligned",)) .note( - "fields of packed structs might be misaligned, and creating \ + "fields of packed structs are not properly aligned, and creating \ a misaligned reference is undefined behavior (even if that \ reference is never dereferenced)", ) diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 0753e9e4b7325..4035417204867 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -217,7 +217,7 @@ declare_lint! { } declare_lint! { - pub PACKED_REFERENCES, + pub UNALIGNED_REFERENCES, Allow, "detects unaligned references to fields of packed structs", } @@ -551,7 +551,7 @@ declare_lint_pass! { INVALID_TYPE_PARAM_DEFAULT, CONST_ERR, RENAMED_AND_REMOVED_LINTS, - PACKED_REFERENCES, + UNALIGNED_REFERENCES, SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, MISSING_FRAGMENT_SPECIFIER, diff --git a/src/test/ui/lint/packed_reference.stderr b/src/test/ui/lint/packed_reference.stderr deleted file mode 100644 index 51158a84175dc..0000000000000 --- a/src/test/ui/lint/packed_reference.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error: reference to packed field is not allowed - --> $DIR/packed_reference.rs:14:17 - | -LL | let _ = &good.data; - | ^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/packed_reference.rs:1:9 - | -LL | #![deny(packed_references)] - | ^^^^^^^^^^^^^^^^^ - = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) - -error: reference to packed field is not allowed - --> $DIR/packed_reference.rs:15:17 - | -LL | let _ = &good.data as *const _; - | ^^^^^^^^^^ - | - = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) - -error: reference to packed field is not allowed - --> $DIR/packed_reference.rs:16:27 - | -LL | let _: *const _ = &good.data; - | ^^^^^^^^^^ - | - = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) - -error: reference to packed field is not allowed - --> $DIR/packed_reference.rs:17:17 - | -LL | let _ = &good.data2[0]; - | ^^^^^^^^^^^^^^ - | - = note: fields of packed structs might be misaligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) - -error: aborting due to 4 previous errors - diff --git a/src/test/ui/lint/packed_reference.rs b/src/test/ui/lint/unaligned_references.rs similarity index 95% rename from src/test/ui/lint/packed_reference.rs rename to src/test/ui/lint/unaligned_references.rs index 349421084682b..1d9f4c3db2eb5 100644 --- a/src/test/ui/lint/packed_reference.rs +++ b/src/test/ui/lint/unaligned_references.rs @@ -1,4 +1,4 @@ -#![deny(packed_references)] +#![deny(unaligned_references)] #[repr(packed)] pub struct Good { diff --git a/src/test/ui/lint/unaligned_references.stderr b/src/test/ui/lint/unaligned_references.stderr new file mode 100644 index 0000000000000..0c594cdb30a3c --- /dev/null +++ b/src/test/ui/lint/unaligned_references.stderr @@ -0,0 +1,39 @@ +error: reference to packed field is unaligned + --> $DIR/unaligned_references.rs:14:17 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unaligned_references.rs:1:9 + | +LL | #![deny(unaligned_references)] + | ^^^^^^^^^^^^^^^^^^^^ + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is unaligned + --> $DIR/unaligned_references.rs:15:17 + | +LL | let _ = &good.data as *const _; + | ^^^^^^^^^^ + | + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is unaligned + --> $DIR/unaligned_references.rs:16:27 + | +LL | let _: *const _ = &good.data; + | ^^^^^^^^^^ + | + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is unaligned + --> $DIR/unaligned_references.rs:17:17 + | +LL | let _ = &good.data2[0]; + | ^^^^^^^^^^^^^^ + | + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: aborting due to 4 previous errors + From 0f18203e85cfa1a140a53938487bbf82917c2e6b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 12:49:15 +0200 Subject: [PATCH 251/695] Miri: refactor read_discriminant and make it return Scalar --- src/librustc_middle/mir/interpret/error.rs | 4 +- src/librustc_mir/interpret/intrinsics.rs | 10 +- src/librustc_mir/interpret/operand.rs | 139 ++++++++++++--------- src/librustc_mir/interpret/step.rs | 3 +- 4 files changed, 86 insertions(+), 70 deletions(-) diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs index d32a147344992..fc588e049d7d8 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/src/librustc_middle/mir/interpret/error.rs @@ -1,4 +1,4 @@ -use super::{AllocId, Pointer, RawConst, ScalarMaybeUninit}; +use super::{AllocId, Pointer, RawConst, Scalar}; use crate::mir::interpret::ConstValue; use crate::ty::layout::LayoutError; @@ -391,7 +391,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Using a non-character `u32` as character. InvalidChar(u32), /// An enum discriminant was set to a value which was outside the range of valid values. - InvalidDiscriminant(ScalarMaybeUninit), + InvalidDiscriminant(Scalar), /// Using a pointer-not-to-a-function as function pointer. InvalidFunctionPointer(Pointer), /// Using a string that is not valid UTF-8, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index fc4be82ad90ad..6c7db9fce4cf0 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -218,15 +218,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::discriminant_value => { let place = self.deref_operand(args[0])?; let discr_val = self.read_discriminant(place.into())?.0; - let scalar = match dest.layout.ty.kind { - ty::Int(_) => Scalar::from_int( - self.sign_extend(discr_val, dest.layout) as i128, - dest.layout.size, - ), - ty::Uint(_) => Scalar::from_uint(discr_val, dest.layout.size), - _ => bug!("invalid `discriminant_value` return layout: {:?}", dest.layout), - }; - self.write_scalar(scalar, dest)?; + self.write_scalar(discr_val, dest)?; } sym::unchecked_shl | sym::unchecked_shr diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index a3caa2048a1e7..7ad16a051fdec 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -15,8 +15,8 @@ use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, Integer, LayoutOf, use rustc_target::abi::{VariantIdx, Variants}; use super::{ - from_known_layout, sign_extend, truncate, ConstValue, GlobalId, InterpCx, InterpResult, - MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, + from_known_layout, ConstValue, GlobalId, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, + Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -577,91 +577,112 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn read_discriminant( &self, rval: OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx, (u128, VariantIdx)> { + ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { trace!("read_discriminant_value {:#?}", rval.layout); - let (discr_layout, discr_kind, discr_index) = match rval.layout.variants { + let (discr_scalar_layout, discr_kind, discr_index) = match rval.layout.variants { Variants::Single { index } => { - let discr_val = rval - .layout - .ty - .discriminant_for_variant(*self.tcx, index) - .map_or(u128::from(index.as_u32()), |discr| discr.val); - return Ok((discr_val, index)); + let discr = match rval.layout.ty.discriminant_for_variant(*self.tcx, index) { + Some(discr) => { + // This type actually has discriminants. + let discr_layout = self.layout_of(discr.ty)?; + Scalar::from_uint(discr.val, discr_layout.size) + } + None => { + // On a type without actual discriminants, return variant idx as `u8`. + let discr_layout = self.layout_of(self.tcx.types.u8)?; + Scalar::from_uint(index.as_u32(), discr_layout.size) + } + }; + return Ok((discr, index)); } - Variants::Multiple { discr: ref discr_layout, ref discr_kind, discr_index, .. } => { - (discr_layout, discr_kind, discr_index) + Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { + (discr, discr_kind, discr_index) } }; - // read raw discriminant value - let discr_op = self.operand_field(rval, discr_index)?; - let discr_val = self.read_immediate(discr_op)?; - let raw_discr = discr_val.to_scalar_or_undef(); - trace!("discr value: {:?}", raw_discr); - // post-process + // There are *three* types/layouts that come into play here: + // - The field storing the discriminant has a layout, which my be a pointer. + // This is `discr_val.layout`; we just use it for sanity checks. + // - The discriminant has a layout for tag storing purposes, which is always an integer. + // This is `discr_layout` and is used to interpret the value we read from the + // discriminant field. + // - The discriminant also has a type for typechecking, and that type's + // layout can be *different*. This is `discr_ty`, and is used for the `Scalar` + // we return. If necessary, a cast from `discr_layout` is performed. + + // Get layout for tag. + let discr_layout = self.layout_of(discr_scalar_layout.value.to_int_ty(*self.tcx))?; + + // Read discriminant value and sanity-check `discr_layout`. + let discr_val = self.read_immediate(self.operand_field(rval, discr_index)?)?; + assert_eq!(discr_layout.size, discr_val.layout.size); + assert_eq!(discr_layout.abi.is_signed(), discr_val.layout.abi.is_signed()); + let discr_val = discr_val.to_scalar()?; + trace!("discriminant value: {:?}", discr_val); + + // Get type used by typechecking. + let discr_ty = match rval.layout.ty.kind { + ty::Adt(adt, _) => { + let discr_int_ty = Integer::from_attr(self, adt.repr.discr_type()); + // The signedness of tag and discriminant is the same. + discr_int_ty.to_ty(*self.tcx, discr_layout.abi.is_signed()) + } + ty::Generator(_, substs, _) => { + let substs = substs.as_generator(); + substs.discr_ty(*self.tcx) + } + _ => bug!("multiple variants for non-adt non-generator"), + }; + + // Figure out which discriminant and variant this corresponds to. Ok(match *discr_kind { DiscriminantKind::Tag => { - let bits_discr = raw_discr - .not_undef() - .and_then(|raw_discr| self.force_bits(raw_discr, discr_val.layout.size)) - .map_err(|_| err_ub!(InvalidDiscriminant(raw_discr.erase_tag())))?; - let real_discr = if discr_val.layout.abi.is_signed() { - // going from layout tag type to typeck discriminant type - // requires first sign extending with the discriminant layout - let sexted = sign_extend(bits_discr, discr_val.layout.size); - // and then zeroing with the typeck discriminant type - let discr_ty = rval - .layout - .ty - .ty_adt_def() - .expect("tagged layout corresponds to adt") - .repr - .discr_type(); - let size = Integer::from_attr(self, discr_ty).size(); - truncate(sexted, size) - } else { - bits_discr - }; - // Make sure we catch invalid discriminants + let discr_bits = self + .force_bits(discr_val, discr_layout.size) + .map_err(|_| err_ub!(InvalidDiscriminant(discr_val.erase_tag())))?; + // Cast discriminant bits to the right type. + let discr_ty_layout = self.layout_of(discr_ty)?; + let discr_val_cast = + self.cast_from_scalar(discr_bits, discr_layout, discr_ty); + let discr_bits = discr_val_cast.assert_bits(discr_ty_layout.size); + // Find variant index for this tag, and catch invalid discriminants. let index = match rval.layout.ty.kind { ty::Adt(adt, _) => { - adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == real_discr) + adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == discr_bits) } ty::Generator(def_id, substs, _) => { let substs = substs.as_generator(); substs .discriminants(def_id, self.tcx.tcx) - .find(|(_, var)| var.val == real_discr) + .find(|(_, var)| var.val == discr_bits) } _ => bug!("tagged layout for non-adt non-generator"), } - .ok_or_else(|| err_ub!(InvalidDiscriminant(raw_discr.erase_tag())))?; - (real_discr, index.0) + .ok_or_else(|| err_ub!(InvalidDiscriminant(discr_val.erase_tag())))?; + // Return the cast value, and the index. + (discr_val_cast, index.0) } DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => { + // Compute the variant this discriminant corresponds to. With niche layout, + // tag and variant index are the same. let variants_start = niche_variants.start().as_u32(); let variants_end = niche_variants.end().as_u32(); - let raw_discr = raw_discr - .not_undef() - .map_err(|_| err_ub!(InvalidDiscriminant(ScalarMaybeUninit::Uninit)))?; - match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) { + let variant = match discr_val.to_bits_or_ptr(discr_layout.size, self) { Err(ptr) => { // The niche must be just 0 (which an inbounds pointer value never is) let ptr_valid = niche_start == 0 && variants_start == variants_end && !self.memory.ptr_may_be_null(ptr); if !ptr_valid { - throw_ub!(InvalidDiscriminant(raw_discr.erase_tag().into())) + throw_ub!(InvalidDiscriminant(discr_val.erase_tag())) } - (u128::from(dataful_variant.as_u32()), dataful_variant) + dataful_variant } - Ok(raw_discr) => { + Ok(bits_discr) => { // We need to use machine arithmetic to get the relative variant idx: // variant_index_relative = discr_val - niche_start_val - let discr_layout = - self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?; - let discr_val = ImmTy::from_uint(raw_discr, discr_layout); + let discr_val = ImmTy::from_uint(bits_discr, discr_layout); let niche_start_val = ImmTy::from_uint(niche_start, discr_layout); let variant_index_relative_val = self.binary_op(mir::BinOp::Sub, discr_val, niche_start_val)?; @@ -684,12 +705,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .variants .len(); assert!(usize::try_from(variant_index).unwrap() < variants_len); - (u128::from(variant_index), VariantIdx::from_u32(variant_index)) + VariantIdx::from_u32(variant_index) } else { - (u128::from(dataful_variant.as_u32()), dataful_variant) + dataful_variant } } - } + }; + // Compute the size of the scalar we need to return. + // FIXME: Why do we not need to do a cast here like we do above? + let size = self.layout_of(discr_ty)?.size; + (Scalar::from_uint(variant.as_u32(), size), variant) } }) } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index fd9815975c19f..bd4df788057e2 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -262,8 +262,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Discriminant(place) => { let op = self.eval_place_to_op(place, None)?; let discr_val = self.read_discriminant(op)?.0; - let size = dest.layout.size; - self.write_scalar(Scalar::from_uint(discr_val, size), dest)?; + self.write_scalar(discr_val, dest)?; } } From 5a3971cdb8694717f56b8c1bc2cd597bb4ac1677 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 12:10:13 +0200 Subject: [PATCH 252/695] comments and refactor variable names --- src/librustc_mir/interpret/operand.rs | 84 +++++++++++++++------------ 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 7ad16a051fdec..17dfe8b656c1a 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -580,7 +580,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { trace!("read_discriminant_value {:#?}", rval.layout); - let (discr_scalar_layout, discr_kind, discr_index) = match rval.layout.variants { + // We use "discriminant" to refer to the value associated with a particualr enum variant. + // This is not to be confused with its "variant index", which is just determining its position in the + // declared list of variants -- they can differ with explicitly assigned discriminants. + // We use "tag" to refer to how the discriminant is encoded in memory, which can be either + // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`). + // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things + // rather confusing. + let (tag_scalar_layout, tag_kind, tag_index) = match rval.layout.variants { Variants::Single { index } => { let discr = match rval.layout.ty.discriminant_for_variant(*self.tcx, index) { Some(discr) => { @@ -602,31 +609,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // There are *three* types/layouts that come into play here: - // - The field storing the discriminant has a layout, which my be a pointer. - // This is `discr_val.layout`; we just use it for sanity checks. - // - The discriminant has a layout for tag storing purposes, which is always an integer. - // This is `discr_layout` and is used to interpret the value we read from the - // discriminant field. - // - The discriminant also has a type for typechecking, and that type's - // layout can be *different*. This is `discr_ty`, and is used for the `Scalar` - // we return. If necessary, a cast from `discr_layout` is performed. + // - The discriminant has a type for typechecking. This is `discr_ty`, and is used for + // the `Scalar` we return. + // - The discriminant gets encoded as a tag/niche, with layout `tag_layout`. + // This is always an integer, and used to interpret the value we read from the + // tag field. For the return value, a cast to `discr_ty` is performed. + // - The field storing the tag has a layout, which is very similar to + // `tag_layout` but may be a pointer. This is `tag_val.layout`; + // we just use it for sanity checks. // Get layout for tag. - let discr_layout = self.layout_of(discr_scalar_layout.value.to_int_ty(*self.tcx))?; + let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?; - // Read discriminant value and sanity-check `discr_layout`. - let discr_val = self.read_immediate(self.operand_field(rval, discr_index)?)?; - assert_eq!(discr_layout.size, discr_val.layout.size); - assert_eq!(discr_layout.abi.is_signed(), discr_val.layout.abi.is_signed()); - let discr_val = discr_val.to_scalar()?; - trace!("discriminant value: {:?}", discr_val); + // Read tag and sanity-check `tag_layout`. + let tag_val = self.read_immediate(self.operand_field(rval, tag_index)?)?; + assert_eq!(tag_layout.size, tag_val.layout.size); + assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); + let tag_val = tag_val.to_scalar()?; + trace!("tag value: {:?}", tag_val); // Get type used by typechecking. let discr_ty = match rval.layout.ty.kind { ty::Adt(adt, _) => { let discr_int_ty = Integer::from_attr(self, adt.repr.discr_type()); // The signedness of tag and discriminant is the same. - discr_int_ty.to_ty(*self.tcx, discr_layout.abi.is_signed()) + discr_int_ty.to_ty(*self.tcx, tag_layout.abi.is_signed()) } ty::Generator(_, substs, _) => { let substs = substs.as_generator(); @@ -636,17 +643,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Figure out which discriminant and variant this corresponds to. - Ok(match *discr_kind { + Ok(match *tag_kind { DiscriminantKind::Tag => { - let discr_bits = self - .force_bits(discr_val, discr_layout.size) - .map_err(|_| err_ub!(InvalidDiscriminant(discr_val.erase_tag())))?; - // Cast discriminant bits to the right type. - let discr_ty_layout = self.layout_of(discr_ty)?; + let tag_bits = self + .force_bits(tag_val, tag_layout.size) + .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; + // Cast bits from tag layout to discriminant layout. + let discr_layout = self.layout_of(discr_ty)?; let discr_val_cast = - self.cast_from_scalar(discr_bits, discr_layout, discr_ty); - let discr_bits = discr_val_cast.assert_bits(discr_ty_layout.size); - // Find variant index for this tag, and catch invalid discriminants. + self.cast_from_scalar(tag_bits, tag_layout, discr_ty); + let discr_bits = discr_val_cast.assert_bits(discr_layout.size); + // Convert discriminant to variant index, and catch invalid discriminants. let index = match rval.layout.ty.kind { ty::Adt(adt, _) => { adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == discr_bits) @@ -659,36 +666,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => bug!("tagged layout for non-adt non-generator"), } - .ok_or_else(|| err_ub!(InvalidDiscriminant(discr_val.erase_tag())))?; + .ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; // Return the cast value, and the index. (discr_val_cast, index.0) } DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => { - // Compute the variant this discriminant corresponds to. With niche layout, - // tag and variant index are the same. + // Compute the variant this niche value/"tag" corresponds to. With niche layout, + // discriminant (encoded in niche/tag) and variant index are the same. let variants_start = niche_variants.start().as_u32(); let variants_end = niche_variants.end().as_u32(); - let variant = match discr_val.to_bits_or_ptr(discr_layout.size, self) { + let variant = match tag_val.to_bits_or_ptr(tag_layout.size, self) { Err(ptr) => { // The niche must be just 0 (which an inbounds pointer value never is) let ptr_valid = niche_start == 0 && variants_start == variants_end && !self.memory.ptr_may_be_null(ptr); if !ptr_valid { - throw_ub!(InvalidDiscriminant(discr_val.erase_tag())) + throw_ub!(InvalidDiscriminant(tag_val.erase_tag())) } dataful_variant } - Ok(bits_discr) => { + Ok(tag_bits) => { // We need to use machine arithmetic to get the relative variant idx: - // variant_index_relative = discr_val - niche_start_val - let discr_val = ImmTy::from_uint(bits_discr, discr_layout); - let niche_start_val = ImmTy::from_uint(niche_start, discr_layout); + // variant_index_relative = tag_val - niche_start_val + let tag_val = ImmTy::from_uint(tag_bits, tag_layout); + let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); let variant_index_relative_val = - self.binary_op(mir::BinOp::Sub, discr_val, niche_start_val)?; + self.binary_op(mir::BinOp::Sub, tag_val, niche_start_val)?; let variant_index_relative = variant_index_relative_val .to_scalar()? - .assert_bits(discr_val.layout.size); + .assert_bits(tag_val.layout.size); // Check if this is in the range that indicates an actual discriminant. if variant_index_relative <= u128::from(variants_end - variants_start) { let variant_index_relative = u32::try_from(variant_index_relative) @@ -712,7 +719,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; // Compute the size of the scalar we need to return. - // FIXME: Why do we not need to do a cast here like we do above? + // No need to cast, because the variant index directly serves as discriminant and is + // encoded in the tag. let size = self.layout_of(discr_ty)?.size; (Scalar::from_uint(variant.as_u32(), size), variant) } From f8f80334872cf63412b0fe2e79b87505af2ba6a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 13:22:13 +0200 Subject: [PATCH 253/695] assert that types without discriminant use variant idx of 0 --- src/librustc_mir/interpret/operand.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 17dfe8b656c1a..81ef8172da77f 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -596,7 +596,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::from_uint(discr.val, discr_layout.size) } None => { - // On a type without actual discriminants, return variant idx as `u8`. + // On a type without actual discriminants, variant is 0. Return variant idx as `u8`. + assert_eq!(index.as_u32(), 0); let discr_layout = self.layout_of(self.tcx.types.u8)?; Scalar::from_uint(index.as_u32(), discr_layout.size) } From d94923ea469b4c104719071a82a4bc051fed77ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 14:51:50 +0200 Subject: [PATCH 254/695] Format and more tracing --- src/librustc_mir/interpret/operand.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 81ef8172da77f..d46e6e387f508 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -642,6 +642,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => bug!("multiple variants for non-adt non-generator"), }; + trace!("discriminant type: {:?}", discr_ty); // Figure out which discriminant and variant this corresponds to. Ok(match *tag_kind { @@ -651,8 +652,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; // Cast bits from tag layout to discriminant layout. let discr_layout = self.layout_of(discr_ty)?; - let discr_val_cast = - self.cast_from_scalar(tag_bits, tag_layout, discr_ty); + let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_ty); let discr_bits = discr_val_cast.assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. let index = match rval.layout.ty.kind { From 64fbe2fc485477406724a68372f4351dc7a08b0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 15:42:35 +0200 Subject: [PATCH 255/695] Add helper method for determining the type of a discriminant --- src/librustc_middle/mir/tcx.rs | 11 +---- src/librustc_middle/ty/sty.rs | 10 +++++ src/librustc_mir/interpret/operand.rs | 63 ++++++++++----------------- 3 files changed, 35 insertions(+), 49 deletions(-) diff --git a/src/librustc_middle/mir/tcx.rs b/src/librustc_middle/mir/tcx.rs index 17edd9f4cb643..174da7db1753d 100644 --- a/src/librustc_middle/mir/tcx.rs +++ b/src/librustc_middle/mir/tcx.rs @@ -5,7 +5,6 @@ use crate::mir::*; use crate::ty::subst::Subst; -use crate::ty::util::IntTypeExt; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; use rustc_target::abi::VariantIdx; @@ -175,15 +174,7 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), Rvalue::Discriminant(ref place) => { - let ty = place.ty(local_decls, tcx).ty; - match ty.kind { - ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx), - ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), - _ => { - // This can only be `0`, for now, so `u8` will suffice. - tcx.types.u8 - } - } + place.ty(local_decls, tcx).ty.discriminant_type(tcx) } Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t), Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize, diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 370702f7f221d..6cee224219b63 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -29,6 +29,7 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::marker::PhantomData; use std::ops::Range; +use ty::util::IntTypeExt; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] #[derive(HashStable, TypeFoldable, Lift)] @@ -2104,6 +2105,15 @@ impl<'tcx> TyS<'tcx> { } } + /// Returns the type of the discriminant of this type. + pub fn discriminant_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match self.kind { + ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx), + ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), + _ => bug!("{:?} does not have a discriminant", self), + } + } + /// When we create a closure, we record its kind (i.e., what trait /// it implements) into its `ClosureSubsts` using a type /// parameter. This is kind of a phantom type, except that the diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index d46e6e387f508..139871310fbf3 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -7,11 +7,11 @@ use std::fmt::Write; use rustc_errors::ErrorReported; use rustc_hir::def::Namespace; use rustc_macros::HashStable; -use rustc_middle::ty::layout::{IntegerExt, PrimitiveExt, TyAndLayout}; +use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; use rustc_middle::ty::Ty; use rustc_middle::{mir, ty}; -use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, Integer, LayoutOf, Size}; +use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ @@ -576,9 +576,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Read discriminant, return the runtime value as well as the variant index. pub fn read_discriminant( &self, - rval: OpTy<'tcx, M::PointerTag>, + op: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { - trace!("read_discriminant_value {:#?}", rval.layout); + trace!("read_discriminant_value {:#?}", op.layout); + + // Get type and layout of the discriminant. + let discr_layout = self.layout_of(op.layout.ty.discriminant_type(*self.tcx))?; + trace!("discriminant type: {:?}", discr_layout.ty); // We use "discriminant" to refer to the value associated with a particualr enum variant. // This is not to be confused with its "variant index", which is just determining its position in the @@ -587,18 +591,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`). // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things // rather confusing. - let (tag_scalar_layout, tag_kind, tag_index) = match rval.layout.variants { + let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants { Variants::Single { index } => { - let discr = match rval.layout.ty.discriminant_for_variant(*self.tcx, index) { + let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) { Some(discr) => { // This type actually has discriminants. - let discr_layout = self.layout_of(discr.ty)?; + assert_eq!(discr.ty, discr_layout.ty); Scalar::from_uint(discr.val, discr_layout.size) } None => { - // On a type without actual discriminants, variant is 0. Return variant idx as `u8`. + // On a type without actual discriminants, variant is 0. assert_eq!(index.as_u32(), 0); - let discr_layout = self.layout_of(self.tcx.types.u8)?; Scalar::from_uint(index.as_u32(), discr_layout.size) } }; @@ -609,41 +612,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; - // There are *three* types/layouts that come into play here: - // - The discriminant has a type for typechecking. This is `discr_ty`, and is used for + // There are *three* layouts that come into play here: + // - The discriminant has a type for typechecking. This is `discr_layout`, and is used for // the `Scalar` we return. - // - The discriminant gets encoded as a tag/niche, with layout `tag_layout`. - // This is always an integer, and used to interpret the value we read from the - // tag field. For the return value, a cast to `discr_ty` is performed. - // - The field storing the tag has a layout, which is very similar to - // `tag_layout` but may be a pointer. This is `tag_val.layout`; - // we just use it for sanity checks. + // - The tag (encoded discriminant) has layout `tag_layout`. This is always an integer type, + // and used to interpret the value we read from the tag field. + // For the return value, a cast to `discr_layout` is performed. + // - The field storing the tag has a layout, which is very similar to `tag_layout` but + // may be a pointer. This is `tag_val.layout`; we just use it for sanity checks. // Get layout for tag. let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?; // Read tag and sanity-check `tag_layout`. - let tag_val = self.read_immediate(self.operand_field(rval, tag_index)?)?; + let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?; assert_eq!(tag_layout.size, tag_val.layout.size); assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); let tag_val = tag_val.to_scalar()?; trace!("tag value: {:?}", tag_val); - // Get type used by typechecking. - let discr_ty = match rval.layout.ty.kind { - ty::Adt(adt, _) => { - let discr_int_ty = Integer::from_attr(self, adt.repr.discr_type()); - // The signedness of tag and discriminant is the same. - discr_int_ty.to_ty(*self.tcx, tag_layout.abi.is_signed()) - } - ty::Generator(_, substs, _) => { - let substs = substs.as_generator(); - substs.discr_ty(*self.tcx) - } - _ => bug!("multiple variants for non-adt non-generator"), - }; - trace!("discriminant type: {:?}", discr_ty); - // Figure out which discriminant and variant this corresponds to. Ok(match *tag_kind { DiscriminantKind::Tag => { @@ -651,11 +638,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .force_bits(tag_val, tag_layout.size) .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; // Cast bits from tag layout to discriminant layout. - let discr_layout = self.layout_of(discr_ty)?; - let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_ty); + let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); let discr_bits = discr_val_cast.assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. - let index = match rval.layout.ty.kind { + let index = match op.layout.ty.kind { ty::Adt(adt, _) => { adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == discr_bits) } @@ -705,7 +691,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let variant_index = variants_start .checked_add(variant_index_relative) .expect("overflow computing absolute variant idx"); - let variants_len = rval + let variants_len = op .layout .ty .ty_adt_def() @@ -722,8 +708,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Compute the size of the scalar we need to return. // No need to cast, because the variant index directly serves as discriminant and is // encoded in the tag. - let size = self.layout_of(discr_ty)?.size; - (Scalar::from_uint(variant.as_u32(), size), variant) + (Scalar::from_uint(variant.as_u32(), discr_layout.size), variant) } }) } From ad7179d2a409faaf45465862f44efe7f989cd71e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 17:24:33 +0200 Subject: [PATCH 256/695] fix discriminant_ty for non-enums --- src/librustc_middle/mir/tcx.rs | 4 +--- src/librustc_middle/ty/mod.rs | 5 +++++ src/librustc_middle/ty/sty.rs | 13 +++++++++---- src/librustc_mir/interpret/operand.rs | 4 ++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/librustc_middle/mir/tcx.rs b/src/librustc_middle/mir/tcx.rs index 174da7db1753d..3e172bd8d2a76 100644 --- a/src/librustc_middle/mir/tcx.rs +++ b/src/librustc_middle/mir/tcx.rs @@ -173,9 +173,7 @@ impl<'tcx> Rvalue<'tcx> { tcx.intern_tup(&[ty, tcx.types.bool]) } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), - Rvalue::Discriminant(ref place) => { - place.ty(local_decls, tcx).ty.discriminant_type(tcx) - } + Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t), Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize, Rvalue::Aggregate(ref ak, ref ops) => match **ak { diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index aad3c6889c3ce..4d050a7b48eac 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -2040,6 +2040,8 @@ impl ReprOptions { self.flags.contains(ReprFlags::HIDE_NICHE) } + /// Returns the discriminant type, given these `repr` options. + /// This must only be called on enums! pub fn discr_type(&self) -> attr::IntType { self.int.unwrap_or(attr::SignedInt(ast::IntTy::Isize)) } @@ -2272,6 +2274,7 @@ impl<'tcx> AdtDef { #[inline] pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option> { + assert!(self.is_enum()); let param_env = tcx.param_env(expr_did); let repr_type = self.repr.discr_type(); match tcx.const_eval_poly(expr_did) { @@ -2308,6 +2311,7 @@ impl<'tcx> AdtDef { &'tcx self, tcx: TyCtxt<'tcx>, ) -> impl Iterator)> + Captures<'tcx> { + assert!(self.is_enum()); let repr_type = self.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); let mut prev_discr = None::>; @@ -2340,6 +2344,7 @@ impl<'tcx> AdtDef { tcx: TyCtxt<'tcx>, variant_index: VariantIdx, ) -> Discr<'tcx> { + assert!(self.is_enum()); let (val, offset) = self.discriminant_def_for_variant(variant_index); let explicit_value = val .and_then(|expr_did| self.eval_explicit_discr(tcx, expr_did)) diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 6cee224219b63..aacca710dd037 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -2097,7 +2097,9 @@ impl<'tcx> TyS<'tcx> { variant_index: VariantIdx, ) -> Option> { match self.kind { - TyKind::Adt(adt, _) => Some(adt.discriminant_for_variant(tcx, variant_index)), + TyKind::Adt(adt, _) if adt.is_enum() => { + Some(adt.discriminant_for_variant(tcx, variant_index)) + } TyKind::Generator(def_id, substs, _) => { Some(substs.as_generator().discriminant_for_variant(def_id, tcx, variant_index)) } @@ -2106,11 +2108,14 @@ impl<'tcx> TyS<'tcx> { } /// Returns the type of the discriminant of this type. - pub fn discriminant_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + pub fn discriminant_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind { - ty::Adt(adt_def, _) => adt_def.repr.discr_type().to_ty(tcx), + ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx), ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), - _ => bug!("{:?} does not have a discriminant", self), + _ => { + // This can only be `0`, for now, so `u8` will suffice. + tcx.types.u8 + } } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 139871310fbf3..f546f6236d777 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -581,10 +581,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("read_discriminant_value {:#?}", op.layout); // Get type and layout of the discriminant. - let discr_layout = self.layout_of(op.layout.ty.discriminant_type(*self.tcx))?; + let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?; trace!("discriminant type: {:?}", discr_layout.ty); - // We use "discriminant" to refer to the value associated with a particualr enum variant. + // We use "discriminant" to refer to the value associated with a particular enum variant. // This is not to be confused with its "variant index", which is just determining its position in the // declared list of variants -- they can differ with explicitly assigned discriminants. // We use "tag" to refer to how the discriminant is encoded in memory, which can be either From a93d31603f80e16a185cda3377c328ae85273325 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Thu, 23 Apr 2020 15:51:12 -0400 Subject: [PATCH 257/695] Fix bug in shebang handling Shebang handling was too agressive in stripping out the first line in cases where it is actually _not_ a shebang, but instead, valid rust (#70528). This is a second attempt at resolving this issue (the first attempt was flawed, for, among other reasons, causing an ICE in certain cases (#71372, #71471). The behavior is now codified by a number of UI tests, but simply: For the first line to be a shebang, the following must all be true: 1. The line must start with `#!` 2. The line must contain a non whitespace character after `#!` 3. The next character in the file, ignoring comments & whitespace must not be `[` I believe this is a strict superset of what we used to allow, so perhaps a crater run is unnecessary, but probably not a terrible idea. --- src/librustc_lexer/src/lib.rs | 26 ++++++--- src/librustc_lexer/src/tests.rs | 57 +++++++++++++++++++ .../parser/shebang/issue-71471-ignore-tidy.rs | 2 + .../shebang/issue-71471-ignore-tidy.stderr | 8 +++ .../ui/parser/shebang/multiline-attrib.rs | 7 +++ src/test/ui/parser/shebang/regular-attrib.rs | 5 ++ .../ui/parser/shebang/shebang-and-attrib.rs | 9 +++ src/test/ui/parser/shebang/shebang-comment.rs | 6 ++ .../parser/shebang/shebang-must-start-file.rs | 6 ++ .../shebang/shebang-must-start-file.stderr | 8 +++ src/test/ui/parser/shebang/sneaky-attrib.rs | 16 ++++++ src/test/ui/parser/shebang/valid-shebang.rs | 6 ++ src/tools/tidy/src/style.rs | 5 ++ 13 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/parser/shebang/issue-71471-ignore-tidy.rs create mode 100644 src/test/ui/parser/shebang/issue-71471-ignore-tidy.stderr create mode 100644 src/test/ui/parser/shebang/multiline-attrib.rs create mode 100644 src/test/ui/parser/shebang/regular-attrib.rs create mode 100644 src/test/ui/parser/shebang/shebang-and-attrib.rs create mode 100644 src/test/ui/parser/shebang/shebang-comment.rs create mode 100644 src/test/ui/parser/shebang/shebang-must-start-file.rs create mode 100644 src/test/ui/parser/shebang/shebang-must-start-file.stderr create mode 100644 src/test/ui/parser/shebang/sneaky-attrib.rs create mode 100644 src/test/ui/parser/shebang/valid-shebang.rs diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index e44feee96607a..fe6785de009a1 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -236,16 +236,28 @@ pub enum Base { } /// `rustc` allows files to have a shebang, e.g. "#!/usr/bin/rustrun", -/// but shebang isn't a part of rust syntax, so this function -/// skips the line if it starts with a shebang ("#!"). -/// Line won't be skipped if it represents a valid Rust syntax -/// (e.g. "#![deny(missing_docs)]"). +/// but shebang isn't a part of rust syntax. pub fn strip_shebang(input: &str) -> Option { - debug_assert!(!input.is_empty()); - if !input.starts_with("#!") || input.starts_with("#![") { + let first_line = input.lines().next()?; + // A shebang is intentionally loosely defined as `#! [non whitespace]` on the first line. + let could_be_shebang = + first_line.starts_with("#!") && first_line[2..].contains(|c| !is_whitespace(c)); + if !could_be_shebang { return None; } - Some(input.find('\n').unwrap_or(input.len())) + let non_whitespace_tokens = tokenize(input).map(|tok| tok.kind).filter(|tok| + !matches!(tok, TokenKind::LineComment | TokenKind::BlockComment { .. } | TokenKind::Whitespace) + ); + let prefix = [TokenKind::Pound, TokenKind::Not, TokenKind::OpenBracket]; + let starts_with_attribute = non_whitespace_tokens.take(3).eq(prefix.iter().copied()); + if starts_with_attribute { + // If the file starts with #![ then it's definitely not a shebang -- it couldn't be + // a rust program since a Rust program can't start with `[` + None + } else { + // It's a #!... and there isn't a `[` in sight, must be a shebang + Some(first_line.len()) + } } /// Parses the first token from the provided input string. diff --git a/src/librustc_lexer/src/tests.rs b/src/librustc_lexer/src/tests.rs index 06fc159fe2516..725799374fc64 100644 --- a/src/librustc_lexer/src/tests.rs +++ b/src/librustc_lexer/src/tests.rs @@ -145,4 +145,61 @@ mod tests { }), ); } + + #[test] + fn test_valid_shebang() { + // https://github.com/rust-lang/rust/issues/70528 + let input = "#!/usr/bin/rustrun\nlet x = 5;"; + assert_eq!(strip_shebang(input), Some(18)); + } + + #[test] + fn test_invalid_shebang_valid_rust_syntax() { + // https://github.com/rust-lang/rust/issues/70528 + let input = "#! [bad_attribute]"; + assert_eq!(strip_shebang(input), None); + } + + #[test] + fn test_shebang_second_line() { + // Because shebangs are interpreted by the kernel, they must be on the first line + let input = "\n#!/bin/bash"; + assert_eq!(strip_shebang(input), None); + } + + #[test] + fn test_shebang_space() { + let input = "#! /bin/bash"; + assert_eq!(strip_shebang(input), Some(input.len())); + } + + #[test] + fn test_shebang_empty_shebang() { + let input = "#! \n[attribute(foo)]"; + assert_eq!(strip_shebang(input), None); + } + + #[test] + fn test_invalid_shebang_comment() { + let input = "#!//bin/ami/a/comment\n["; + assert_eq!(strip_shebang(input), None) + } + + #[test] + fn test_invalid_shebang_another_comment() { + let input = "#!/*bin/ami/a/comment*/\n[attribute"; + assert_eq!(strip_shebang(input), None) + } + + #[test] + fn test_shebang_valid_rust_after() { + let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; + assert_eq!(strip_shebang(input), Some(23)) + } + + #[test] + fn test_shebang_followed_by_attrib() { + let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; + assert_eq!(strip_shebang(input), Some(19)); + } } diff --git a/src/test/ui/parser/shebang/issue-71471-ignore-tidy.rs b/src/test/ui/parser/shebang/issue-71471-ignore-tidy.rs new file mode 100644 index 0000000000000..a2505180884aa --- /dev/null +++ b/src/test/ui/parser/shebang/issue-71471-ignore-tidy.rs @@ -0,0 +1,2 @@ + +#!B //~ expected `[`, found `B` diff --git a/src/test/ui/parser/shebang/issue-71471-ignore-tidy.stderr b/src/test/ui/parser/shebang/issue-71471-ignore-tidy.stderr new file mode 100644 index 0000000000000..896a9dc83d8b9 --- /dev/null +++ b/src/test/ui/parser/shebang/issue-71471-ignore-tidy.stderr @@ -0,0 +1,8 @@ +error: expected `[`, found `B` + --> $DIR/issue-71471-ignore-tidy.rs:2:3 + | +LL | #!B + | ^ expected `[` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/shebang/multiline-attrib.rs b/src/test/ui/parser/shebang/multiline-attrib.rs new file mode 100644 index 0000000000000..931c94c7fba03 --- /dev/null +++ b/src/test/ui/parser/shebang/multiline-attrib.rs @@ -0,0 +1,7 @@ +#! +[allow(unused_variables)] +// check-pass + +fn main() { + let x = 5; +} diff --git a/src/test/ui/parser/shebang/regular-attrib.rs b/src/test/ui/parser/shebang/regular-attrib.rs new file mode 100644 index 0000000000000..ca8fb0830ffb1 --- /dev/null +++ b/src/test/ui/parser/shebang/regular-attrib.rs @@ -0,0 +1,5 @@ +#![allow(unused_variables)] +// check-pass +fn main() { + let x = 5; +} diff --git a/src/test/ui/parser/shebang/shebang-and-attrib.rs b/src/test/ui/parser/shebang/shebang-and-attrib.rs new file mode 100644 index 0000000000000..61b89c655a3fc --- /dev/null +++ b/src/test/ui/parser/shebang/shebang-and-attrib.rs @@ -0,0 +1,9 @@ +#!/usr/bin/env run-cargo-script + +// check-pass +#![allow(unused_variables)] + + +fn main() { + let x = 5; +} diff --git a/src/test/ui/parser/shebang/shebang-comment.rs b/src/test/ui/parser/shebang/shebang-comment.rs new file mode 100644 index 0000000000000..2b1ab0c574d26 --- /dev/null +++ b/src/test/ui/parser/shebang/shebang-comment.rs @@ -0,0 +1,6 @@ +#!//bin/bash + +// check-pass +fn main() { + println!("a valid shebang (that is also a rust comment)") +} diff --git a/src/test/ui/parser/shebang/shebang-must-start-file.rs b/src/test/ui/parser/shebang/shebang-must-start-file.rs new file mode 100644 index 0000000000000..e0392572dc81d --- /dev/null +++ b/src/test/ui/parser/shebang/shebang-must-start-file.rs @@ -0,0 +1,6 @@ +// something on the first line for tidy +#!/bin/bash //~ expected `[`, found `/` + +fn main() { + println!("ok!"); +} diff --git a/src/test/ui/parser/shebang/shebang-must-start-file.stderr b/src/test/ui/parser/shebang/shebang-must-start-file.stderr new file mode 100644 index 0000000000000..50543e8bdb816 --- /dev/null +++ b/src/test/ui/parser/shebang/shebang-must-start-file.stderr @@ -0,0 +1,8 @@ +error: expected `[`, found `/` + --> $DIR/shebang-must-start-file.rs:2:3 + | +LL | #!/bin/bash + | ^ expected `[` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/shebang/sneaky-attrib.rs b/src/test/ui/parser/shebang/sneaky-attrib.rs new file mode 100644 index 0000000000000..b406cc3aa13c7 --- /dev/null +++ b/src/test/ui/parser/shebang/sneaky-attrib.rs @@ -0,0 +1,16 @@ +#!//bin/bash + + +// This could not possibly be a shebang & also a valid rust file, since a Rust file +// can't start with `[` +/* + [ (mixing comments to also test that we ignore both types of comments) + + */ + +[allow(unused_variables)] + +// check-pass +fn main() { + let x = 5; +} diff --git a/src/test/ui/parser/shebang/valid-shebang.rs b/src/test/ui/parser/shebang/valid-shebang.rs new file mode 100644 index 0000000000000..e480d3da3fc8d --- /dev/null +++ b/src/test/ui/parser/shebang/valid-shebang.rs @@ -0,0 +1,6 @@ +#!/usr/bin/env run-cargo-script + +// check-pass +fn main() { + println!("Hello World!"); +} diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 4247fcb3b7f53..396d6c0cfcdef 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -174,6 +174,11 @@ pub fn check(path: &Path, bad: &mut bool) { let can_contain = contents.contains("// ignore-tidy-") || contents.contains("# ignore-tidy-"); + // Enable testing ICE's that require specific (untidy) + // file formats easily eg. `issue-1234-ignore-tidy.rs` + if filename.contains("ignore-tidy") { + return; + } let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr"); let mut skip_undocumented_unsafe = contains_ignore_directive(can_contain, &contents, "undocumented-unsafe"); From 7a83eafd44b57196a454d10628d1cce1bfd60bd2 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Mon, 25 May 2020 17:11:07 +0200 Subject: [PATCH 258/695] Also fetch origin before merging master into the rustup branch --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9180e58fc251..0f47ac98fd20a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -183,8 +183,8 @@ to be run inside the `rust` directory): `rust-clippy` repo (this has to be done in the Clippy repo, not in the rust-copy of Clippy): ```bash + git fetch origin && git fetch upstream git checkout sync-from-rust - git fetch upstream git merge upstream/master ``` 3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to From b6eec22dd49b74eda4257d0fd634fa179de9c2ec Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Tue, 26 May 2020 02:44:55 +0900 Subject: [PATCH 259/695] Fix typo in src/libcore/num/f32.rs Co-authored-by: bluss --- src/libcore/num/f32.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 47f489c40abb1..56c77c8aea0c0 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -874,7 +874,7 @@ impl f32 { // flip the exponent and mantissa bits in case of negative numbers. // We effectively convert the numbers to "two's complement" form. if left < 0 { - // i32::MAX corresponds the bit pattern of "all ones expect for the sign bit" + // i32::MAX corresponds the bit pattern of "all ones except for the sign bit" left ^= i32::MAX }; if right < 0 { From d6650e0d2b1027de341ba7f48937eab499fca3ee Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Tue, 26 May 2020 02:45:06 +0900 Subject: [PATCH 260/695] Fix typo in src/libcore/num/f32.rs Co-authored-by: bluss --- src/libcore/num/f32.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 56c77c8aea0c0..813e3077c3b8a 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -858,7 +858,7 @@ impl f32 { let mut left = self.to_bits() as i32; let mut right = other.to_bits() as i32; - // In case of negatives, flip all the bits expect the sign + // In case of negatives, flip all the bits except the sign // to achieve a similar layout as two's complement integers // // Why does this work? IEEE 754 floats consist of three fields: From cff5cff2f3a6687dfaf12b92762e70545e0abefe Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Fri, 22 May 2020 22:30:28 +0200 Subject: [PATCH 261/695] Make the name of the crate available in cargo UI tests --- clippy_dev/src/new_lint.rs | 17 ++++++++++++----- .../cargo_common_metadata/fail/src/main.rs | 1 + .../cargo_common_metadata/pass/src/main.rs | 1 + .../multiple_crate_versions/fail/src/main.rs | 1 + .../multiple_crate_versions/pass/src/main.rs | 1 + .../wildcard_dependencies/fail/src/main.rs | 1 + .../wildcard_dependencies/pass/src/main.rs | 1 + 7 files changed, 18 insertions(+), 5 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 08a2e0c0918f0..c0b2dac2f60ff 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -76,7 +76,8 @@ fn create_test(lint: &LintData) -> io::Result<()> { path.push("src"); fs::create_dir(&path)?; - write_file(path.join("main.rs"), get_test_file_contents(lint_name))?; + let header = format!("// compile-flags: --crate-name={}", lint_name); + write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?; Ok(()) } @@ -90,7 +91,7 @@ fn create_test(lint: &LintData) -> io::Result<()> { create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint") } else { let test_path = format!("tests/ui/{}.rs", lint.name); - let test_contents = get_test_file_contents(lint.name); + let test_contents = get_test_file_contents(lint.name, None); write_file(lint.project_root.join(test_path), test_contents) } } @@ -119,8 +120,8 @@ fn to_camel_case(name: &str) -> String { .collect() } -fn get_test_file_contents(lint_name: &str) -> String { - format!( +fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String { + let mut contents = format!( "#![warn(clippy::{})] fn main() {{ @@ -128,7 +129,13 @@ fn main() {{ }} ", lint_name - ) + ); + + if let Some(header) = header_commands { + contents = format!("{}\n{}", header, contents); + } + + contents } fn get_manifest_contents(lint_name: &str, hint: &str) -> String { diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs index c67166fc4b007..27841e18aa9ef 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs @@ -1,3 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs index c67166fc4b007..27841e18aa9ef 100644 --- a/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs +++ b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs @@ -1,3 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs index 4bc61dd62992f..1b2d3ec9459f9 100644 --- a/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs +++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs @@ -1,3 +1,4 @@ +// compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs index 4bc61dd62992f..1b2d3ec9459f9 100644 --- a/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs +++ b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs @@ -1,3 +1,4 @@ +// compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs index 3491ccb0d47d5..581babfeacbff 100644 --- a/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs +++ b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs @@ -1,3 +1,4 @@ +// compile-flags: --crate-name=wildcard_dependencies #![warn(clippy::wildcard_dependencies)] fn main() {} diff --git a/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs index 3491ccb0d47d5..581babfeacbff 100644 --- a/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs +++ b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs @@ -1,3 +1,4 @@ +// compile-flags: --crate-name=wildcard_dependencies #![warn(clippy::wildcard_dependencies)] fn main() {} From 8642fc97dd1a9b4f0291726c47ec97d15599d74d Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Fri, 22 May 2020 22:39:19 +0200 Subject: [PATCH 262/695] multiple_crate_versions: skip dev and build deps --- clippy_lints/src/multiple_crate_versions.rs | 59 ++++++++++++++----- .../5041_allow_dev_build/Cargo.toml | 17 ++++++ .../5041_allow_dev_build/src/main.rs | 4 ++ 3 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml create mode 100644 tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index c4decfc940111..b24ec897ef5ad 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -1,11 +1,14 @@ //! lint on multiple versions of a crate being used use crate::utils::{run_lints, span_lint}; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{Crate, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::DUMMY_SP; +use cargo_metadata::{DependencyKind, MetadataCommand, Node, Package, PackageId}; +use if_chain::if_chain; use itertools::Itertools; declare_clippy_lint! { @@ -34,37 +37,65 @@ declare_clippy_lint! { declare_lint_pass!(MultipleCrateVersions => [MULTIPLE_CRATE_VERSIONS]); impl LateLintPass<'_, '_> for MultipleCrateVersions { + #[allow(clippy::find_map)] fn check_crate(&mut self, cx: &LateContext<'_, '_>, _: &Crate<'_>) { if !run_lints(cx, &[MULTIPLE_CRATE_VERSIONS], CRATE_HIR_ID) { return; } - let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().exec() { + let metadata = if let Ok(metadata) = MetadataCommand::new().exec() { metadata } else { span_lint(cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, "could not read cargo metadata"); - return; }; + let local_name = cx.tcx.crate_name(LOCAL_CRATE).as_str(); let mut packages = metadata.packages; packages.sort_by(|a, b| a.name.cmp(&b.name)); - for (name, group) in &packages.into_iter().group_by(|p| p.name.clone()) { - let group: Vec = group.collect(); + if_chain! { + if let Some(resolve) = &metadata.resolve; + if let Some(local_id) = packages.iter().find(|p| p.name == *local_name).map(|p| &p.id); + then { + for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { + let group: Vec<&Package> = group.collect(); + + if group.len() <= 1 { + continue; + } - if group.len() > 1 { - let mut versions: Vec<_> = group.into_iter().map(|p| p.version).collect(); - versions.sort(); - let versions = versions.iter().join(", "); + if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) { + let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect(); + versions.sort(); + let versions = versions.iter().join(", "); - span_lint( - cx, - MULTIPLE_CRATE_VERSIONS, - DUMMY_SP, - &format!("multiple versions for dependency `{}`: {}", name, versions), - ); + span_lint( + cx, + MULTIPLE_CRATE_VERSIONS, + DUMMY_SP, + &format!("multiple versions for dependency `{}`: {}", name, versions), + ); + } + } } } } } + +fn is_normal_dep(nodes: &[Node], local_id: &PackageId, dep_id: &PackageId) -> bool { + fn depends_on(node: &Node, dep_id: &PackageId) -> bool { + node.deps.iter().any(|dep| { + dep.pkg == *dep_id + && dep + .dep_kinds + .iter() + .any(|info| matches!(info.kind, DependencyKind::Normal)) + }) + } + + nodes + .iter() + .filter(|node| depends_on(node, dep_id)) + .any(|node| node.id == *local_id || is_normal_dep(nodes, local_id, &node.id)) +} diff --git a/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml new file mode 100644 index 0000000000000..72731fbc75d00 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml @@ -0,0 +1,17 @@ +# Should not lint for dev or build dependencies. See issue 5041. + +[package] +name = "multiple_crate_versions" +version = "0.1.0" +publish = false + +# One of the versions of winapi is only a dev dependency: allowed +[dependencies] +ctrlc = "=3.1.0" +[dev-dependencies] +ansi_term = "=0.11.0" + +# Both versions of winapi are a build dependency: allowed +[build-dependencies] +ctrlc = "=3.1.0" +ansi_term = "=0.11.0" diff --git a/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs new file mode 100644 index 0000000000000..1b2d3ec9459f9 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=multiple_crate_versions +#![warn(clippy::multiple_crate_versions)] + +fn main() {} From ec0a00e53980619a6313ff4f01099a1aebcfd9e6 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sun, 24 May 2020 21:17:54 +0200 Subject: [PATCH 263/695] Use find_map instead of find() + map() --- clippy_lints/src/multiple_crate_versions.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index b24ec897ef5ad..b6770804e1801 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -37,7 +37,6 @@ declare_clippy_lint! { declare_lint_pass!(MultipleCrateVersions => [MULTIPLE_CRATE_VERSIONS]); impl LateLintPass<'_, '_> for MultipleCrateVersions { - #[allow(clippy::find_map)] fn check_crate(&mut self, cx: &LateContext<'_, '_>, _: &Crate<'_>) { if !run_lints(cx, &[MULTIPLE_CRATE_VERSIONS], CRATE_HIR_ID) { return; @@ -56,7 +55,9 @@ impl LateLintPass<'_, '_> for MultipleCrateVersions { if_chain! { if let Some(resolve) = &metadata.resolve; - if let Some(local_id) = packages.iter().find(|p| p.name == *local_name).map(|p| &p.id); + if let Some(local_id) = packages + .iter() + .find_map(|p| if p.name == *local_name { Some(&p.id) } else { None }); then { for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { let group: Vec<&Package> = group.collect(); From 4f8909fad986dda68a9dcd172eaa362b6fce105b Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 9 May 2020 21:28:31 +0200 Subject: [PATCH 264/695] Extend `useless_conversion` lint with TryFrom --- clippy_lints/src/useless_conversion.rs | 47 ++++++++++++++++++++------ clippy_lints/src/utils/paths.rs | 1 + tests/ui/useless_conversion.stderr | 20 +++++------ tests/ui/useless_conversion_try.rs | 25 ++++++++++++++ tests/ui/useless_conversion_try.stderr | 39 +++++++++++++++++++++ 5 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 tests/ui/useless_conversion_try.rs create mode 100644 tests/ui/useless_conversion_try.stderr diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 95921518986bc..0b080d9be2c06 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,13 +1,16 @@ use crate::utils::{ - match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_sugg, + is_type_diagnostic_item, match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, + span_lint_and_help, span_lint_and_sugg, }; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for `Into`/`From`/`IntoIter` calls that useless converts + /// **What it does:** Checks for `Into`, `From`, `TryFrom`,`IntoIter` calls that useless converts /// to the same type as caller. /// /// **Why is this bad?** Redundant code. @@ -26,7 +29,7 @@ declare_clippy_lint! { /// ``` pub USELESS_CONVERSION, complexity, - "calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type" + "calls to `Into`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type" } #[derive(Default)] @@ -68,7 +71,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion", + "Useless conversion to the same type", "consider removing `.into()`", sugg, Applicability::MachineApplicable, // snippet @@ -84,7 +87,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion", + "Useless conversion to the same type", "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -94,11 +97,35 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { }, ExprKind::Call(ref path, ref args) => { - if let ExprKind::Path(ref qpath) = path.kind { - if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id() { + if_chain! { + if args.len() == 1; + if let ExprKind::Path(ref qpath) = path.kind; + if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id(); + let a = cx.tables.expr_ty(e); + let b = cx.tables.expr_ty(&args[0]); + + then { + if_chain! { + if match_def_path(cx, def_id, &paths::TRY_FROM); + if is_type_diagnostic_item(cx, a, sym!(result_type)); + if let ty::Adt(_, substs) = a.kind; + if let Some(a_type) = substs.types().nth(0); + if same_tys(cx, a_type, b); + + then { + let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); + span_lint_and_help( + cx, + USELESS_CONVERSION, + e.span, + "Useless conversion to the same type", + None, + &hint, + ); + } + } + if match_def_path(cx, def_id, &paths::FROM_FROM) { - let a = cx.tables.expr_ty(e); - let b = cx.tables.expr_ty(&args[0]); if same_tys(cx, a, b) { let sugg = snippet(cx, args[0].span.source_callsite(), "").into_owned(); let sugg_msg = @@ -107,7 +134,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion", + "Useless conversion to the same type", &sugg_msg, sugg, Applicability::MachineApplicable, // snippet diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index b3ad2ad9d9987..e00d726282a41 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -128,6 +128,7 @@ pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned" pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"]; pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"]; pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; +pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"]; pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"]; pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"]; pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"]; diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 7df3507edfd9e..0b2947f7d6282 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,4 +1,4 @@ -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:6:13 | LL | let _ = T::from(val); @@ -10,55 +10,55 @@ note: the lint level is defined here LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:7:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:19:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:51:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:52:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:53:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:54:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:55:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:56:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` -error: useless conversion +error: Useless conversion to the same type --> $DIR/useless_conversion.rs:57:21 | LL | let _: String = format!("Hello {}", "world").into(); diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs new file mode 100644 index 0000000000000..abf0c891b5205 --- /dev/null +++ b/tests/ui/useless_conversion_try.rs @@ -0,0 +1,25 @@ +#![deny(clippy::useless_conversion)] + +use std::convert::TryFrom; + +fn test_generic(val: T) -> T { + T::try_from(val).unwrap() +} + +fn test_generic2 + Into, U: From>(val: T) { + let _ = U::try_from(val).unwrap(); +} + +fn main() { + test_generic(10i32); + test_generic2::(10i32); + + let _: String = TryFrom::try_from("foo").unwrap(); + let _ = String::try_from("foo").unwrap(); + #[allow(clippy::useless_conversion)] + let _ = String::try_from("foo").unwrap(); + + let _: String = TryFrom::try_from("foo".to_string()).unwrap(); + let _ = String::try_from("foo".to_string()).unwrap(); + let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); +} diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr new file mode 100644 index 0000000000000..b3cb01fbe3243 --- /dev/null +++ b/tests/ui/useless_conversion_try.stderr @@ -0,0 +1,39 @@ +error: Useless conversion to the same type + --> $DIR/useless_conversion_try.rs:6:5 + | +LL | T::try_from(val).unwrap() + | ^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/useless_conversion_try.rs:1:9 + | +LL | #![deny(clippy::useless_conversion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider removing `T::try_from()` + +error: Useless conversion to the same type + --> $DIR/useless_conversion_try.rs:22:21 + | +LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `TryFrom::try_from()` + +error: Useless conversion to the same type + --> $DIR/useless_conversion_try.rs:23:13 + | +LL | let _ = String::try_from("foo".to_string()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `String::try_from()` + +error: Useless conversion to the same type + --> $DIR/useless_conversion_try.rs:24:13 + | +LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `String::try_from()` + +error: aborting due to 4 previous errors + From 705bfdcc467c0ddd7eb61d3adb24809b27bae891 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Fri, 22 May 2020 11:46:17 +0200 Subject: [PATCH 265/695] Extend `useless_conversion` lint with TryInto --- clippy_lints/src/useless_conversion.rs | 38 +++++++++++++++++++++----- clippy_lints/src/utils/paths.rs | 1 + src/lintlist/mod.rs | 2 +- tests/ui/useless_conversion_try.rs | 17 +++++++++--- tests/ui/useless_conversion_try.stderr | 38 +++++++++++++++++++++----- 5 files changed, 77 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 0b080d9be2c06..1645c5777b26b 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -10,8 +10,8 @@ use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for `Into`, `From`, `TryFrom`,`IntoIter` calls that useless converts - /// to the same type as caller. + /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls + /// that useless converts to the same type as caller. /// /// **Why is this bad?** Redundant code. /// @@ -29,7 +29,7 @@ declare_clippy_lint! { /// ``` pub USELESS_CONVERSION, complexity, - "calls to `Into`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type" + "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type" } #[derive(Default)] @@ -39,6 +39,7 @@ pub struct UselessConversion { impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]); +#[allow(clippy::too_many_lines)] impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) { if e.span.from_expansion() { @@ -66,7 +67,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { let b = cx.tables.expr_ty(&args[0]); if same_tys(cx, a, b) { let sugg = snippet_with_macro_callsite(cx, args[0].span, "").to_string(); - span_lint_and_sugg( cx, USELESS_CONVERSION, @@ -94,6 +94,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { ); } } + if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" { + if_chain! { + let a = cx.tables.expr_ty(e); + let b = cx.tables.expr_ty(&args[0]); + if is_type_diagnostic_item(cx, a, sym!(result_type)); + if let ty::Adt(_, substs) = a.kind; + if let Some(a_type) = substs.types().next(); + if same_tys(cx, a_type, b); + + then { + span_lint_and_help( + cx, + USELESS_CONVERSION, + e.span, + "Useless conversion to the same type", + None, + "consider removing `.try_into()`", + ); + } + } + } }, ExprKind::Call(ref path, ref args) => { @@ -109,7 +130,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { if match_def_path(cx, def_id, &paths::TRY_FROM); if is_type_diagnostic_item(cx, a, sym!(result_type)); if let ty::Adt(_, substs) = a.kind; - if let Some(a_type) = substs.types().nth(0); + if let Some(a_type) = substs.types().next(); if same_tys(cx, a_type, b); then { @@ -125,8 +146,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { } } - if match_def_path(cx, def_id, &paths::FROM_FROM) { - if same_tys(cx, a, b) { + if_chain! { + if match_def_path(cx, def_id, &paths::FROM_FROM); + if same_tys(cx, a, b); + + then { let sugg = snippet(cx, args[0].span.source_callsite(), "").into_owned(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index e00d726282a41..779da7e6bf23c 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -131,6 +131,7 @@ pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"]; pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"]; pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"]; +pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"]; pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"]; pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8211a57b56439..f63301c7db0a6 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2421,7 +2421,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "useless_conversion", group: "complexity", - desc: "calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type", + desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type", deprecation: None, module: "useless_conversion", }, diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index abf0c891b5205..ab4f960edb7ef 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -1,12 +1,16 @@ #![deny(clippy::useless_conversion)] -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; fn test_generic(val: T) -> T { - T::try_from(val).unwrap() + let _ = T::try_from(val).unwrap(); + val.try_into().unwrap() } fn test_generic2 + Into, U: From>(val: T) { + // ok + let _: i32 = val.try_into().unwrap(); + let _: U = val.try_into().unwrap(); let _ = U::try_from(val).unwrap(); } @@ -14,12 +18,17 @@ fn main() { test_generic(10i32); test_generic2::(10i32); + let _: String = "foo".try_into().unwrap(); let _: String = TryFrom::try_from("foo").unwrap(); let _ = String::try_from("foo").unwrap(); #[allow(clippy::useless_conversion)] - let _ = String::try_from("foo").unwrap(); - + { + let _ = String::try_from("foo").unwrap(); + let _: String = "foo".try_into().unwrap(); + } + let _: String = "foo".to_string().try_into().unwrap(); let _: String = TryFrom::try_from("foo".to_string()).unwrap(); let _ = String::try_from("foo".to_string()).unwrap(); let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); + let _: String = format!("Hello {}", "world").try_into().unwrap(); } diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index b3cb01fbe3243..5afb5dc45d364 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -1,8 +1,8 @@ error: Useless conversion to the same type - --> $DIR/useless_conversion_try.rs:6:5 + --> $DIR/useless_conversion_try.rs:6:13 | -LL | T::try_from(val).unwrap() - | ^^^^^^^^^^^^^^^^ +LL | let _ = T::try_from(val).unwrap(); + | ^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/useless_conversion_try.rs:1:9 @@ -12,7 +12,23 @@ LL | #![deny(clippy::useless_conversion)] = help: consider removing `T::try_from()` error: Useless conversion to the same type - --> $DIR/useless_conversion_try.rs:22:21 + --> $DIR/useless_conversion_try.rs:7:5 + | +LL | val.try_into().unwrap() + | ^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: Useless conversion to the same type + --> $DIR/useless_conversion_try.rs:29:21 + | +LL | let _: String = "foo".to_string().try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: Useless conversion to the same type + --> $DIR/useless_conversion_try.rs:30:21 | LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +36,7 @@ LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); = help: consider removing `TryFrom::try_from()` error: Useless conversion to the same type - --> $DIR/useless_conversion_try.rs:23:13 + --> $DIR/useless_conversion_try.rs:31:13 | LL | let _ = String::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,12 +44,20 @@ LL | let _ = String::try_from("foo".to_string()).unwrap(); = help: consider removing `String::try_from()` error: Useless conversion to the same type - --> $DIR/useless_conversion_try.rs:24:13 + --> $DIR/useless_conversion_try.rs:32:13 | LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider removing `String::try_from()` -error: aborting due to 4 previous errors +error: Useless conversion to the same type + --> $DIR/useless_conversion_try.rs:33:21 + | +LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: aborting due to 7 previous errors From 827041252c709dee70756633a33a13a0bacbd3a9 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 23 May 2020 09:35:56 +0200 Subject: [PATCH 266/695] Add common lint tools doc --- doc/adding_lints.md | 1 + doc/common_tools_writing_lints.md | 152 ++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 doc/common_tools_writing_lints.md diff --git a/doc/adding_lints.md b/doc/adding_lints.md index b3f5a62d55307..8092be277cca0 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -465,6 +465,7 @@ Here are some pointers to things you are likely going to need for every lint: * [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro] * [`Span`][span] * [`Applicability`][applicability] +* [Common tools for writing lints](common_tools_writing_lints.md) helps with common operations * [The rustc-dev-guide][rustc-dev-guide] explains a lot of internal compiler concepts * [The nightly rustc docs][nightly_docs] which has been linked to throughout this guide diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md new file mode 100644 index 0000000000000..ed33b37c6bd1b --- /dev/null +++ b/doc/common_tools_writing_lints.md @@ -0,0 +1,152 @@ +# Common tools for writing lints + +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) + - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait) + - [Dealing with macros](#dealing-with-macros) + +Useful Rustc dev guide links: +- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation) +- [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 + +Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for example to answer following questions: + +- which type does this expression correspond to (using its [`TyKind`][TyKind])? +- is it a sized type? +- is it a primitive type? +- does it implement a trait? + +This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct, +that gives you access to the underlying structure [`TyS`][TyS]. + +Example of use: +```rust +impl LateLintPass<'_, '_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + // Get type of `expr` + let ty = cx.tables.expr_ty(expr); + // Match its kind to enter its type + match ty.kind { + ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"), + _ => () + } + } +} +``` + +Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method +to retrieve a type from a pattern. + +Two noticeable items here: +- `cx` is the lint context [`LateContext`][LateContext]. + The two most useful data structures in this context are `tcx` and `tables`, + allowing us to jump to type definitions and other compilation stages such as HIR. +- `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step, + it includes useful information such as types of expressions, ways to resolve methods and so on. + +# Checking if a type implements a specific trait + +There are two ways to do this, depending if the target trait is part of lang items. + +```rust +use crate::utils::{implements_trait, match_trait_method, paths}; + +impl LateLintPass<'_, '_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + // 1. Using expression and Clippy's convenient method + // we use `match_trait_method` function from Clippy's toolbox + if match_trait_method(cx, expr, &paths::INTO) { + // `expr` implements `Into` trait + } + + // 2. Using type context `TyCtxt` + let ty = cx.tables.expr_ty(expr); + if cx.tcx.lang_items() + // we are looking for the `DefId` of `Drop` trait in lang items + .drop_trait() + // then we use it with our type `ty` by calling `implements_trait` from Clippy's utils + .map_or(false, |id| implements_trait(cx, ty, id, &[])) { + // `expr` implements `Drop` trait + } + } +} +``` + +> Prefer using lang items, if the target trait is available there. + +A list of defined paths for Clippy can be found in [paths.rs][paths] + +We access lang items through the type context `tcx`. `tcx` is of type [`TyCtxt`][TyCtxt] and is defined in the `rustc_middle` crate. + +# Dealing with macros + +There are several helpers in Clippy's utils to deal with macros: + +- `in_macro()`: detect if the given span is expanded by a macro + +You may want to use this for example to not start linting in any macro. + +```rust +macro_rules! foo { + ($param:expr) => { + match $param { + "bar" => println!("whatever"), + _ => () + } + }; +} + +foo!("bar"); + +// if we lint the `match` of `foo` call and test its span +assert_eq!(in_macro(match_span), true); +``` + +- `in_external_macro()`: detect if the given span is from an external macro, defined in a foreign crate + +You may want to use it for example to not start linting in macros from other crates + +```rust +#[macro_use] +extern crate a_crate_with_macros; + +// `foo` is defined in `a_crate_with_macros` +foo!("bar"); + +// if we lint the `match` of `foo` call and test its span +assert_eq!(in_external_macro(cx.sess(), match_span), true); +``` + +- `differing_macro_contexts()`: returns true if the two given spans are not from the same context + +```rust +macro_rules! m { + ($a:expr, $b:expr) => { + if $a.is_some() { + $b; + } + } +} + +let x: Option = Some(42); +m!(x, x.unwrap()); + +// These spans are not from the same context +// x.is_some() is from inside the macro +// x.unwrap() is from outside the macro +assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true); +``` + +[TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[TypeckTables]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html +[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html#method.expr_ty +[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html +[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckTables.html#method.pat_ty +[paths]: ../clippy_lints/src/utils/paths.rs From 60d38ee1dde4344daa5fdf716eef78b45f483c7e Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Sat, 23 May 2020 22:07:03 +0200 Subject: [PATCH 267/695] reversed_empty_ranges: add suggestion for &slice[N..N] --- clippy_lints/src/ranges.rs | 30 ++++++++++++++----- tests/ui/reversed_empty_ranges_fixable.fixed | 7 ++++- tests/ui/reversed_empty_ranges_fixable.rs | 7 ++++- tests/ui/reversed_empty_ranges_fixable.stderr | 16 ++++++---- tests/ui/reversed_empty_ranges_unfixable.rs | 1 - .../ui/reversed_empty_ranges_unfixable.stderr | 10 ++----- 6 files changed, 47 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 83c6faac04149..1eb26d97ed4d2 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -241,14 +241,14 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { } fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { - fn inside_indexing_expr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { - matches!( - get_parent_expr(cx, expr), - Some(Expr { + fn inside_indexing_expr<'a>(cx: &'a LateContext<'_, '_>, expr: &Expr<'_>) -> Option<&'a Expr<'a>> { + match get_parent_expr(cx, expr) { + parent_expr @ Some(Expr { kind: ExprKind::Index(..), .. - }) - ) + }) => parent_expr, + _ => None, + } } fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool { @@ -267,18 +267,32 @@ fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); if is_empty_range(limits, ordering); then { - if inside_indexing_expr(cx, expr) { + if let Some(parent_expr) = inside_indexing_expr(cx, expr) { let (reason, outcome) = if ordering == Ordering::Equal { ("empty", "always yield an empty slice") } else { ("reversed", "panic at run-time") }; - span_lint( + span_lint_and_then( cx, REVERSED_EMPTY_RANGES, expr.span, &format!("this range is {} and using it to index a slice will {}", reason, outcome), + |diag| { + if_chain! { + if ordering == Ordering::Equal; + if let ty::Slice(slice_ty) = cx.tables.expr_ty(parent_expr).kind; + then { + diag.span_suggestion( + parent_expr.span, + "if you want an empty slice, use", + format!("[] as &[{}]", slice_ty), + Applicability::MaybeIncorrect + ); + } + } + } ); } else { span_lint_and_then( diff --git a/tests/ui/reversed_empty_ranges_fixable.fixed b/tests/ui/reversed_empty_ranges_fixable.fixed index ee2cbc3cf540e..332c0427ef65a 100644 --- a/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/tests/ui/reversed_empty_ranges_fixable.fixed @@ -4,18 +4,23 @@ const ANSWER: i32 = 42; fn main() { + let arr = [1, 2, 3, 4, 5]; + + // These should be linted: + (21..=42).rev().for_each(|x| println!("{}", x)); let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::>(); for _ in (-42..=-21).rev() {} for _ in (21u32..42u32).rev() {} + let _ = &[] as &[i32]; + // These should be ignored as they are not empty ranges: (21..=42).for_each(|x| println!("{}", x)); (21..42).for_each(|x| println!("{}", x)); - let arr = [1, 2, 3, 4, 5]; let _ = &arr[1..=3]; let _ = &arr[1..3]; diff --git a/tests/ui/reversed_empty_ranges_fixable.rs b/tests/ui/reversed_empty_ranges_fixable.rs index 6ed5ca6daa0e8..901ec8bcc09f4 100644 --- a/tests/ui/reversed_empty_ranges_fixable.rs +++ b/tests/ui/reversed_empty_ranges_fixable.rs @@ -4,18 +4,23 @@ const ANSWER: i32 = 42; fn main() { + let arr = [1, 2, 3, 4, 5]; + + // These should be linted: + (42..=21).for_each(|x| println!("{}", x)); let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); for _ in -21..=-42 {} for _ in 42u32..21u32 {} + let _ = &arr[3..3]; + // These should be ignored as they are not empty ranges: (21..=42).for_each(|x| println!("{}", x)); (21..42).for_each(|x| println!("{}", x)); - let arr = [1, 2, 3, 4, 5]; let _ = &arr[1..=3]; let _ = &arr[1..3]; diff --git a/tests/ui/reversed_empty_ranges_fixable.stderr b/tests/ui/reversed_empty_ranges_fixable.stderr index 97933b8ff8515..9a646fd99398d 100644 --- a/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/tests/ui/reversed_empty_ranges_fixable.stderr @@ -1,5 +1,5 @@ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:7:5 + --> $DIR/reversed_empty_ranges_fixable.rs:11:5 | LL | (42..=21).for_each(|x| println!("{}", x)); | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL | (21..=42).rev().for_each(|x| println!("{}", x)); | ^^^^^^^^^^^^^^^ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:8:13 + --> $DIR/reversed_empty_ranges_fixable.rs:12:13 | LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect:: $DIR/reversed_empty_ranges_fixable.rs:10:14 + --> $DIR/reversed_empty_ranges_fixable.rs:14:14 | LL | for _ in -21..=-42 {} | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | for _ in (-42..=-21).rev() {} | ^^^^^^^^^^^^^^^^^ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:11:14 + --> $DIR/reversed_empty_ranges_fixable.rs:15:14 | LL | for _ in 42u32..21u32 {} | ^^^^^^^^^^^^ @@ -43,5 +43,11 @@ help: consider using the following if you are attempting to iterate over this ra LL | for _ in (21u32..42u32).rev() {} | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: this range is empty and using it to index a slice will always yield an empty slice + --> $DIR/reversed_empty_ranges_fixable.rs:17:18 + | +LL | let _ = &arr[3..3]; + | ----^^^^- help: if you want an empty slice, use: `[] as &[i32]` + +error: aborting due to 5 previous errors diff --git a/tests/ui/reversed_empty_ranges_unfixable.rs b/tests/ui/reversed_empty_ranges_unfixable.rs index c9ca4c4766831..561a35625f02e 100644 --- a/tests/ui/reversed_empty_ranges_unfixable.rs +++ b/tests/ui/reversed_empty_ranges_unfixable.rs @@ -9,7 +9,6 @@ fn main() { let arr = [1, 2, 3, 4, 5]; let _ = &arr[3usize..=1usize]; let _ = &arr[SOME_NUM..1]; - let _ = &arr[3..3]; for _ in ANSWER..ANSWER {} } diff --git a/tests/ui/reversed_empty_ranges_unfixable.stderr b/tests/ui/reversed_empty_ranges_unfixable.stderr index 12e5483ecdfff..240188cbb46cb 100644 --- a/tests/ui/reversed_empty_ranges_unfixable.stderr +++ b/tests/ui/reversed_empty_ranges_unfixable.stderr @@ -18,17 +18,11 @@ error: this range is reversed and using it to index a slice will panic at run-ti LL | let _ = &arr[SOME_NUM..1]; | ^^^^^^^^^^^ -error: this range is empty and using it to index a slice will always yield an empty slice - --> $DIR/reversed_empty_ranges_unfixable.rs:12:18 - | -LL | let _ = &arr[3..3]; - | ^^^^ - error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_unfixable.rs:14:14 + --> $DIR/reversed_empty_ranges_unfixable.rs:13:14 | LL | for _ in ANSWER..ANSWER {} | ^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors From 91f52a51a23f8c5e8c82c49bbf3ab1bb781d3b02 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Mon, 25 May 2020 15:16:31 -0400 Subject: [PATCH 268/695] impl AsRef<[T]> for vec::IntoIter --- src/liballoc/vec.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index d26cd77aae4b7..9e887cf446e70 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2603,6 +2603,13 @@ impl IntoIter { } } +#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] +impl AsRef<[T]> for IntoIter { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for IntoIter {} #[stable(feature = "rust1", since = "1.0.0")] From 6bd9cd99a3da53bdda4530dde9f737a843de6c91 Mon Sep 17 00:00:00 2001 From: Jeremy Stucki Date: Wed, 21 Aug 2019 21:18:43 +0200 Subject: [PATCH 269/695] Add tests --- tests/ui/or_fun_call.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 7599b945a9137..522f31b72d01f 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -95,6 +95,15 @@ fn test_or_with_ctors() { let b = "b".to_string(); let _ = Some(Bar("a".to_string(), Duration::from_secs(1))) .or(Some(Bar(b, Duration::from_secs(2)))); + + let vec = vec!["foo"]; + let _ = opt.ok_or(vec.len()); + + let array = ["foo"]; + let _ = opt.ok_or(array.len()); + + let slice = &["foo"][..]; + let _ = opt.ok_or(slice.len()); } // Issue 4514 - early return From 566377f6272b0a3b9fa65dabe1f39ee82be80d4e Mon Sep 17 00:00:00 2001 From: Jeremy Stucki Date: Wed, 21 Aug 2019 21:19:28 +0200 Subject: [PATCH 270/695] Ignore calls to 'len' --- clippy_lints/src/methods/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 32b3b7f7947f6..c82cf57a4b1f1 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1614,6 +1614,21 @@ fn lint_or_fun_call<'a, 'tcx>( or_has_args: bool, span: Span, ) { + if let hir::ExprKind::MethodCall(ref path, _, ref args) = &arg.node { + if path.ident.as_str() == "len" { + let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0])); + + match ty.sty { + ty::Slice(_) | ty::Array(_, _) => return, + _ => (), + } + + if match_type(cx, ty, &paths::VEC) { + return; + } + } + } + // (path, fn_has_argument, methods, suffix) let know_types: &[(&[_], _, &[_], _)] = &[ (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), From bcfeb4de1589c19a7b21f04fec284e6045c0aa7a Mon Sep 17 00:00:00 2001 From: Jeremy Stucki Date: Mon, 25 May 2020 21:23:39 +0200 Subject: [PATCH 271/695] Fix build --- 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 c82cf57a4b1f1..52ca962e7ef97 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1614,11 +1614,11 @@ fn lint_or_fun_call<'a, 'tcx>( or_has_args: bool, span: Span, ) { - if let hir::ExprKind::MethodCall(ref path, _, ref args) = &arg.node { + if let hir::ExprKind::MethodCall(ref path, _, ref args) = &arg.kind { if path.ident.as_str() == "len" { let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0])); - match ty.sty { + match ty.kind { ty::Slice(_) | ty::Array(_, _) => return, _ => (), } From d9f55322cccf1e1ca1b996f8431f7ff8836d5d55 Mon Sep 17 00:00:00 2001 From: Jeremy Stucki Date: Mon, 25 May 2020 21:38:46 +0200 Subject: [PATCH 272/695] Update ui test --- tests/ui/or_fun_call.fixed | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 8ea03fe42616c..7bb08797ef396 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -95,6 +95,15 @@ fn test_or_with_ctors() { let b = "b".to_string(); let _ = Some(Bar("a".to_string(), Duration::from_secs(1))) .or(Some(Bar(b, Duration::from_secs(2)))); + + let vec = vec!["foo"]; + let _ = opt.ok_or(vec.len()); + + let array = ["foo"]; + let _ = opt.ok_or(array.len()); + + let slice = &["foo"][..]; + let _ = opt.ok_or(slice.len()); } // Issue 4514 - early return From 4ca626258ae9a677c4d63fa278847eb90e514868 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 23 May 2020 20:01:36 +0200 Subject: [PATCH 273/695] Avoid `Operand::Copy` with `&mut T` --- src/librustc_mir/shim.rs | 2 +- src/librustc_mir/transform/instcombine.rs | 19 ++++++++++++------- .../rustc.a.Inline.after.mir | 2 +- .../rustc.b.Inline.after.mir | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index e3982c654d5fa..b439e919050c0 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -700,7 +700,7 @@ fn build_call_shim<'tcx>( let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment { Adjustment::Identity => Operand::Move(rcvr_place()), - Adjustment::Deref => Operand::Copy(tcx.mk_place_deref(rcvr_place())), + Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), // Can't copy `&mut` Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())), Adjustment::RefMut => { // let rcvr = &mut rcvr; diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index dee37f767e979..a016892d982d1 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -1,11 +1,11 @@ //! Performs various peephole optimizations. use crate::transform::{MirPass, MirSource}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::Idx; use rustc_middle::mir::visit::{MutVisitor, Visitor}; use rustc_middle::mir::{ - Body, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, + Body, Constant, Local, Location, Mutability, Operand, Place, PlaceRef, ProjectionElem, Rvalue, }; use rustc_middle::ty::{self, TyCtxt}; use std::mem; @@ -39,7 +39,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { } fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { - if self.optimizations.and_stars.remove(&location) { + if let Some(mtbl) = self.optimizations.and_stars.remove(&location) { debug!("replacing `&*`: {:?}", rvalue); let new_place = match rvalue { Rvalue::Ref(_, _, place) => { @@ -57,7 +57,10 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { } _ => bug!("Detected `&*` but didn't find `&*`!"), }; - *rvalue = Rvalue::Use(Operand::Copy(new_place)) + *rvalue = Rvalue::Use(match mtbl { + Mutability::Mut => Operand::Move(new_place), + Mutability::Not => Operand::Copy(new_place), + }); } if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { @@ -88,8 +91,10 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } = place.as_ref() { - if Place::ty_from(local, proj_base, self.body, self.tcx).ty.is_region_ptr() { - self.optimizations.and_stars.insert(location); + // The dereferenced place must have type `&_`. + let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty; + if let ty::Ref(_, _, mtbl) = ty.kind { + self.optimizations.and_stars.insert(location, mtbl); } } } @@ -109,6 +114,6 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { #[derive(Default)] struct OptimizationList<'tcx> { - and_stars: FxHashSet, + and_stars: FxHashMap, arrays_lengths: FxHashMap>, } diff --git a/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.a.Inline.after.mir b/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.a.Inline.after.mir index 2eebf3f0eceb9..8751469d265a2 100644 --- a/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.a.Inline.after.mir +++ b/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.a.Inline.after.mir @@ -15,7 +15,7 @@ fn a(_1: &mut [T]) -> &mut [T] { StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 - _3 = _4; // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + _3 = move _4; // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:14: 3:15 _0 = &mut (*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 diff --git a/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.b.Inline.after.mir b/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.b.Inline.after.mir index f9e1699c55dfa..743da27a049f9 100644 --- a/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.b.Inline.after.mir @@ -18,7 +18,7 @@ fn b(_1: &mut std::boxed::Box) -> &mut T { _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 StorageLive(_5); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL _5 = &mut (*(*_4)); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL - _3 = _5; // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL + _3 = move _5; // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL StorageDead(_5); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:14: 8:15 From e04318e0fa5429e1ac44b624b9a775cfeeed66ed Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 24 May 2020 00:55:44 +0200 Subject: [PATCH 274/695] Add a small MIR validation pass --- src/librustc_interface/tests.rs | 1 + src/librustc_mir/transform/mod.rs | 14 ++++- src/librustc_mir/transform/validate.rs | 80 ++++++++++++++++++++++++++ src/librustc_session/options.rs | 2 + 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/librustc_mir/transform/validate.rs diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 0394821d09569..d573e11fc4b24 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -511,6 +511,7 @@ fn test_debugging_options_tracking_hash() { untracked!(ui_testing, true); untracked!(unpretty, Some("expanded".to_string())); untracked!(unstable_options, true); + untracked!(validate_mir, true); untracked!(verbose, true); macro_rules! tracked { diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 0551ed5a15ddb..95a5752348374 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -39,6 +39,7 @@ pub mod simplify_branches; pub mod simplify_try; pub mod uninhabited_enum_branching; pub mod unreachable_prop; +pub mod validate; pub(crate) fn provide(providers: &mut Providers<'_>) { self::check_unsafety::provide(providers); @@ -147,12 +148,18 @@ pub fn run_passes( passes: &[&[&dyn MirPass<'tcx>]], ) { let phase_index = mir_phase.phase_index(); + let source = MirSource { instance, promoted }; + let validate = tcx.sess.opts.debugging_opts.validate_mir; if body.phase >= mir_phase { return; } - let source = MirSource { instance, promoted }; + if validate { + validate::Validator { when: format!("input to phase {:?}", mir_phase) } + .run_pass(tcx, source, body); + } + let mut index = 0; let mut run_pass = |pass: &dyn MirPass<'tcx>| { let run_hooks = |body: &_, index, is_after| { @@ -169,6 +176,11 @@ pub fn run_passes( pass.run_pass(tcx, source, body); run_hooks(body, index, true); + if validate { + validate::Validator { when: format!("after {} in phase {:?}", pass.name(), mir_phase) } + .run_pass(tcx, source, body); + } + index += 1; }; diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs new file mode 100644 index 0000000000000..a25edd131baa1 --- /dev/null +++ b/src/librustc_mir/transform/validate.rs @@ -0,0 +1,80 @@ +//! Validates the MIR to ensure that invariants are upheld. + +use super::{MirPass, MirSource}; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::{ + mir::{Body, Location, Operand, Rvalue, Statement, StatementKind}, + ty::{ParamEnv, TyCtxt}, +}; +use rustc_span::{def_id::DefId, Span, DUMMY_SP}; + +pub struct Validator { + /// Describes at which point in the pipeline this validation is happening. + pub when: String, +} + +impl<'tcx> MirPass<'tcx> for Validator { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + let def_id = source.def_id(); + let param_env = tcx.param_env(def_id); + TypeChecker { when: &self.when, def_id, body, tcx, param_env }.visit_body(body); + } +} + +struct TypeChecker<'a, 'tcx> { + when: &'a str, + def_id: DefId, + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, +} + +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + fn fail(&self, span: Span, msg: impl AsRef) { + // We use `delay_span_bug` as we might see broken MIR when other errors have already + // occurred. + self.tcx.sess.diagnostic().delay_span_bug( + span, + &format!("broken MIR in {:?} ({}): {}", self.def_id, self.when, msg.as_ref()), + ); + } +} + +impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { + // `Operand::Copy` is only supposed to be used with `Copy` types. + if let Operand::Copy(place) = operand { + let ty = place.ty(&self.body.local_decls, self.tcx).ty; + + if !ty.is_copy_modulo_regions(self.tcx, self.param_env, DUMMY_SP) { + self.fail( + DUMMY_SP, + format!("`Operand::Copy` with non-`Copy` type {} at {:?}", ty, location), + ); + } + } + + self.super_operand(operand, location); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + // The sides of an assignment must not alias. Currently this just checks whether the places + // are identical. + if let StatementKind::Assign(box (dest, rvalue)) = &statement.kind { + match rvalue { + Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => { + if dest == src { + self.fail( + DUMMY_SP, + format!( + "encountered `Assign` statement with overlapping memory at {:?}", + location + ), + ); + } + } + _ => {} + } + } + } +} diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 3b6c21e7de008..95f9ff00fb8d4 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -1045,6 +1045,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], "use legacy .ctors section for initializers rather than .init_array"), + validate_mir: bool = (false, parse_bool, [UNTRACKED], + "validate MIR after each transformation"), verbose: bool = (false, parse_bool, [UNTRACKED], "in general, enable more debug printouts (default: no)"), verify_llvm_ir: bool = (false, parse_bool, [TRACKED], From 91dcbbbf50baa02d0757085bb5a9bd69bae5a5a4 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 25 May 2020 20:45:26 +0530 Subject: [PATCH 275/695] Allow unlabeled breaks from desugared `?` in labeled blocks --- src/librustc_passes/loops.rs | 3 ++- .../ui/label/label_break_value_desugared_break.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/label/label_break_value_desugared_break.rs diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 09b3d44020d81..767a6909d31d4 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -9,6 +9,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_span::hygiene::DesugaringKind; use rustc_span::Span; #[derive(Clone, Copy, Debug, PartialEq)] @@ -203,7 +204,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { label: &Destination, cf_type: &str, ) -> bool { - if self.cx == LabeledBlock { + if !span.is_desugaring(DesugaringKind::QuestionMark) && self.cx == LabeledBlock { if label.label.is_none() { struct_span_err!( self.sess, diff --git a/src/test/ui/label/label_break_value_desugared_break.rs b/src/test/ui/label/label_break_value_desugared_break.rs new file mode 100644 index 0000000000000..de883b61111ce --- /dev/null +++ b/src/test/ui/label/label_break_value_desugared_break.rs @@ -0,0 +1,12 @@ +// compile-flags: --edition 2018 +#![feature(label_break_value, try_blocks)] + +// run-pass +fn main() { + let _: Result<(), ()> = try { + 'foo: { + Err(())?; + break 'foo; + } + }; +} From fe1753af840527bb2beba3ee603971312299b2e7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 25 May 2020 22:04:48 +0200 Subject: [PATCH 276/695] Always validate MIR after optimizing --- src/librustc_mir/transform/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 95a5752348374..af9436d404180 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -191,6 +191,11 @@ pub fn run_passes( } body.phase = mir_phase; + + if mir_phase == MirPhase::Optimized { + validate::Validator { when: format!("end of phase {:?}", mir_phase) } + .run_pass(tcx, source, body); + } } fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs { From bd68de89b55d7f7d7adc41fdcd0a5bac1f805692 Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Tue, 26 May 2020 02:48:56 +0900 Subject: [PATCH 277/695] remove unneeded and unidiomatic must_use --- src/libcore/num/f32.rs | 1 - src/libcore/num/f64.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 813e3077c3b8a..36b70587385cb 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -851,7 +851,6 @@ impl f32 { /// # .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter()) /// # .all(|(a, b)| a.to_bits() == b.to_bits())) /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "total_cmp", issue = "none")] #[inline] pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 9c02180838014..61711df3c65ef 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -865,7 +865,6 @@ impl f64 { /// # .zip([-5.0, 0.1, 10.0, 99.0, f64::INFINITY, f64::NAN].iter()) /// # .all(|(a, b)| a.to_bits() == b.to_bits())) /// ``` - #[must_use = "method returns a new number and does not mutate the original value"] #[unstable(feature = "total_cmp", issue = "none")] #[inline] pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { From 6973fd716b51b01debf39edd8e43f0059be3d053 Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Tue, 26 May 2020 04:50:53 +0900 Subject: [PATCH 278/695] Add bit twiddling --- src/libcore/num/f32.rs | 18 ++++++++++-------- src/libcore/num/f64.rs | 16 +++++++++------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 36b70587385cb..538cca712ca95 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -857,7 +857,7 @@ impl f32 { let mut left = self.to_bits() as i32; let mut right = other.to_bits() as i32; - // In case of negatives, flip all the bits except the sign + // In case of negatives, flip all the bits expect the sign // to achieve a similar layout as two's complement integers // // Why does this work? IEEE 754 floats consist of three fields: @@ -872,13 +872,15 @@ impl f32 { // To easily compare the floats as signed integers, we need to // flip the exponent and mantissa bits in case of negative numbers. // We effectively convert the numbers to "two's complement" form. - if left < 0 { - // i32::MAX corresponds the bit pattern of "all ones except for the sign bit" - left ^= i32::MAX - }; - if right < 0 { - right ^= i32::MAX - }; + // + // To do the flipping, we construct a mask and XOR against it. + // We branchlessly calculate an "all-ones expect for the sign bit" + // mask from negative-signed values: right shifting sign-extends + // the integer, so we "fill" the mask with sign bits, and then + // convert to unsigned to push one more zero bit. + // On positive values, the mask is all zeros, so it's a no-op. + left ^= (((left >> 31) as u32) >> 1) as i32; + right ^= (((right >> 31) as u32) >> 1) as i32; left.cmp(&right) } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 61711df3c65ef..b3ebceb77c2e5 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -886,13 +886,15 @@ impl f64 { // To easily compare the floats as signed integers, we need to // flip the exponent and mantissa bits in case of negative numbers. // We effectively convert the numbers to "two's complement" form. - if left < 0 { - // i64::MAX corresponds the bit pattern of "all ones expect for the sign bit" - left ^= i64::MAX - }; - if right < 0 { - right ^= i64::MAX - }; + // + // To do the flipping, we construct a mask and XOR against it. + // We branchlessly calculate an "all-ones expect for the sign bit" + // mask from negative-signed values: right shifting sign-extends + // the integer, so we "fill" the mask with sign bits, and then + // convert to unsigned to push one more zero bit. + // On positive values, the mask is all zeros, so it's a no-op. + left ^= (((left >> 63) as u64) >> 1) as i64; + right ^= (((right >> 63) as u64) >> 1) as i64; left.cmp(&right) } From 8bc31ff9055c50e9d882dd56909dc0b40c3a6453 Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Tue, 26 May 2020 04:54:50 +0900 Subject: [PATCH 279/695] Fix the same typos again orz --- src/libcore/num/f32.rs | 4 ++-- src/libcore/num/f64.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 538cca712ca95..c54bfb27dfe5c 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -857,7 +857,7 @@ impl f32 { let mut left = self.to_bits() as i32; let mut right = other.to_bits() as i32; - // In case of negatives, flip all the bits expect the sign + // In case of negatives, flip all the bits except the sign // to achieve a similar layout as two's complement integers // // Why does this work? IEEE 754 floats consist of three fields: @@ -874,7 +874,7 @@ impl f32 { // We effectively convert the numbers to "two's complement" form. // // To do the flipping, we construct a mask and XOR against it. - // We branchlessly calculate an "all-ones expect for the sign bit" + // We branchlessly calculate an "all-ones except for the sign bit" // mask from negative-signed values: right shifting sign-extends // the integer, so we "fill" the mask with sign bits, and then // convert to unsigned to push one more zero bit. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index b3ebceb77c2e5..18d5d720a0544 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -871,7 +871,7 @@ impl f64 { let mut left = self.to_bits() as i64; let mut right = other.to_bits() as i64; - // In case of negatives, flip all the bits expect the sign + // In case of negatives, flip all the bits except the sign // to achieve a similar layout as two's complement integers // // Why does this work? IEEE 754 floats consist of three fields: @@ -888,7 +888,7 @@ impl f64 { // We effectively convert the numbers to "two's complement" form. // // To do the flipping, we construct a mask and XOR against it. - // We branchlessly calculate an "all-ones expect for the sign bit" + // We branchlessly calculate an "all-ones except for the sign bit" // mask from negative-signed values: right shifting sign-extends // the integer, so we "fill" the mask with sign bits, and then // convert to unsigned to push one more zero bit. From 08df3116e92356311735be2d0c588d461e16fbff Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 24 Apr 2020 00:17:29 -0700 Subject: [PATCH 280/695] librustc_mir: Add support for const fn offset/arith_offset Miri's pointer_offset_inbounds implementation has been moved into librustc_mir as ptr_offset_inbounds (to avoid breaking miri on a nightly update). The comments have been slightly reworked to better match `offset`'s external documentation about what causes UB. The intrinsic implementations are taken directly from miri. Signed-off-by: Joe Richey --- src/librustc_mir/interpret/intrinsics.rs | 53 +++++++++++++++++++++++- src/librustc_span/symbol.rs | 2 + 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index fc4be82ad90ad..0db9c7026588d 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -10,11 +10,11 @@ use rustc_middle::mir::{ }; use rustc_middle::ty; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size}; -use super::{ImmTy, InterpCx, Machine, OpTy, PlaceTy}; +use super::{CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy}; mod caller_location; mod type_name; @@ -279,7 +279,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = Scalar::from_uint(truncated_bits, layout.size); self.write_scalar(result, dest)?; } + sym::offset => { + let ptr = self.read_scalar(args[0])?.not_undef()?; + let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?; + let pointee_ty = substs.type_at(0); + let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; + self.write_scalar(offset_ptr, dest)?; + } + sym::arith_offset => { + let ptr = self.read_scalar(args[0])?.not_undef()?; + let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?; + let pointee_ty = substs.type_at(0); + + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); + let offset_bytes = offset_count.wrapping_mul(pointee_size); + let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self); + self.write_scalar(offset_ptr, dest)?; + } sym::ptr_offset_from => { let a = self.read_immediate(args[0])?.to_scalar()?; let b = self.read_immediate(args[1])?.to_scalar()?; @@ -409,4 +426,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `Rem` says this is all right, so we can let `Div` do its job. self.binop_ignore_overflow(BinOp::Div, a, b, dest) } + + /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its + /// allocation. For integer pointers, we consider each of them their own tiny allocation of size + /// 0, so offset-by-0 (and only 0) is okay -- except that NULL cannot be offset by _any_ value. + pub fn ptr_offset_inbounds( + &self, + ptr: Scalar, + pointee_ty: Ty<'tcx>, + offset_count: i64, + ) -> InterpResult<'tcx, Scalar> { + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); + // The computed offset, in bytes, cannot overflow an isize. + let offset_bytes = offset_count + .checked_mul(pointee_size) + .ok_or(err_ub_format!("inbounds pointer arithmetic: overflow computing offset"))?; + // The offset being in bounds cannot rely on "wrapping around" the address space. + // So, first rule out overflows in the pointer arithmetic. + let offset_ptr = ptr.ptr_signed_offset(offset_bytes, self)?; + // ptr and offset_ptr must be in bounds of the same allocated object. This means all of the + // memory between these pointers must be accessible. Note that we do not require the + // pointers to be properly aligned (unlike a read/write operation). + let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; + let size = offset_bytes.checked_abs().unwrap(); + // This call handles checking for integer/NULL pointers. + self.memory.check_ptr_access_align( + min_ptr, + Size::from_bytes(size), + None, + CheckInAllocMsg::InboundsTest, + )?; + Ok(offset_ptr) + } } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 6a6098710e828..9b055beb99dfd 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -147,6 +147,7 @@ symbols! { Arc, Arguments, ArgumentV1, + arith_offset, arm_target_feature, asm, assert, @@ -516,6 +517,7 @@ symbols! { not, note, object_safe_for_dispatch, + offset, Ok, omit_gdb_pretty_printer_section, on, From 9b3dfd8ea987ce1d4b5ccbcb4c032f60a71c8cfb Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 24 Apr 2020 00:19:11 -0700 Subject: [PATCH 281/695] core: Make pointer offset methods "const fn" Signed-off-by: Joe Richey --- src/libcore/intrinsics.rs | 2 ++ src/libcore/lib.rs | 1 + src/libcore/ptr/const_ptr.rs | 18 ++++++++++++------ src/libcore/ptr/mut_ptr.rs | 18 ++++++++++++------ 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 9006e4cfaf7bb..2d97fecf8a766 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1314,6 +1314,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`std::pointer::offset`](../../std/primitive.pointer.html#method.offset). #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] pub fn offset(dst: *const T, offset: isize) -> *const T; /// Calculates the offset from a pointer, potentially wrapping. @@ -1331,6 +1332,7 @@ extern "rust-intrinsic" { /// The stabilized version of this intrinsic is /// [`std::pointer::wrapping_offset`](../../std/primitive.pointer.html#method.wrapping_offset). #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] pub fn arith_offset(dst: *const T, offset: isize) -> *const T; /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ca13433caec8d..7d21f9a9a66d0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -85,6 +85,7 @@ #![feature(const_panic)] #![feature(const_fn_union)] #![feature(const_generics)] +#![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_result)] #![feature(const_slice_from_raw_parts)] diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 85ba5fc0638ea..835183d171a79 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -151,8 +151,9 @@ impl *const T { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn offset(self, count: isize) -> *const T + pub const unsafe fn offset(self, count: isize) -> *const T where T: Sized, { @@ -210,8 +211,9 @@ impl *const T { /// ``` #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_offset(self, count: isize) -> *const T + pub const fn wrapping_offset(self, count: isize) -> *const T where T: Sized, { @@ -393,8 +395,9 @@ impl *const T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn add(self, count: usize) -> Self + pub const unsafe fn add(self, count: usize) -> Self where T: Sized, { @@ -455,8 +458,9 @@ impl *const T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn sub(self, count: usize) -> Self + pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, { @@ -511,8 +515,9 @@ impl *const T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_add(self, count: usize) -> Self + pub const fn wrapping_add(self, count: usize) -> Self where T: Sized, { @@ -567,8 +572,9 @@ impl *const T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_sub(self, count: usize) -> Self + pub const fn wrapping_sub(self, count: usize) -> Self where T: Sized, { diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 0781d7e6cac45..40b5e4e22340e 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -145,8 +145,9 @@ impl *mut T { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn offset(self, count: isize) -> *mut T + pub const unsafe fn offset(self, count: isize) -> *mut T where T: Sized, { @@ -203,8 +204,9 @@ impl *mut T { /// ``` #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_offset(self, count: isize) -> *mut T + pub const fn wrapping_offset(self, count: isize) -> *mut T where T: Sized, { @@ -439,8 +441,9 @@ impl *mut T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn add(self, count: usize) -> Self + pub const unsafe fn add(self, count: usize) -> Self where T: Sized, { @@ -501,8 +504,9 @@ impl *mut T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub unsafe fn sub(self, count: usize) -> Self + pub const unsafe fn sub(self, count: usize) -> Self where T: Sized, { @@ -557,8 +561,9 @@ impl *mut T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_add(self, count: usize) -> Self + pub const fn wrapping_add(self, count: usize) -> Self where T: Sized, { @@ -613,8 +618,9 @@ impl *mut T { /// ``` #[stable(feature = "pointer_methods", since = "1.26.0")] #[must_use = "returns a new pointer rather than modifying its argument"] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn wrapping_sub(self, count: usize) -> Self + pub const fn wrapping_sub(self, count: usize) -> Self where T: Sized, { From 88a37a20867a3b9840d2f56f806f77ec0990d50c Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 15 May 2020 01:28:33 -0700 Subject: [PATCH 282/695] test/ui/consts: Add tests for const ptr offsets Signed-off-by: Joe Richey --- src/test/ui/consts/offset.rs | 115 +++++++++++++++++++++ src/test/ui/consts/offset_ub.rs | 22 ++++ src/test/ui/consts/offset_ub.stderr | 154 ++++++++++++++++++++++++++++ 3 files changed, 291 insertions(+) create mode 100644 src/test/ui/consts/offset.rs create mode 100644 src/test/ui/consts/offset_ub.rs create mode 100644 src/test/ui/consts/offset_ub.stderr diff --git a/src/test/ui/consts/offset.rs b/src/test/ui/consts/offset.rs new file mode 100644 index 0000000000000..f64242d568e31 --- /dev/null +++ b/src/test/ui/consts/offset.rs @@ -0,0 +1,115 @@ +// run-pass +#![feature(const_ptr_offset)] +#![feature(const_ptr_offset_from)] +#![feature(ptr_offset_from)] +use std::ptr; + +#[repr(C)] +struct Struct { + a: u32, + b: u32, + c: u32, +} +static S: Struct = Struct { a: 0, b: 0, c: 0 }; + +// For these tests we use offset_from to check that two pointers are equal. +// Rust doesn't currently support comparing pointers in const fn. + +static OFFSET_NO_CHANGE: bool = unsafe { + let p1 = &S.b as *const u32; + let p2 = p1.offset(2).offset(-2); + p1.offset_from(p2) == 0 +}; +static OFFSET_MIDDLE: bool = unsafe { + let p1 = (&S.a as *const u32).offset(1); + let p2 = (&S.c as *const u32).offset(-1); + p1.offset_from(p2) == 0 +}; +// Pointing to the end of the allocation is OK +static OFFSET_END: bool = unsafe { + let p1 = (&S.a as *const u32).offset(3); + let p2 = (&S.c as *const u32).offset(1); + p1.offset_from(p2) == 0 +}; +// Casting though a differently sized type is OK +static OFFSET_U8_PTR: bool = unsafe { + let p1 = (&S.a as *const u32 as *const u8).offset(5); + let p2 = (&S.c as *const u32 as *const u8).offset(-3); + p1.offset_from(p2) == 0 +}; +// Any offset with a ZST does nothing +const OFFSET_ZST: bool = unsafe { + let pz = &() as *const (); + // offset_from can't work with ZSTs, so cast to u8 ptr + let p1 = pz.offset(5) as *const u8; + let p2 = pz.offset(isize::MIN) as *const u8; + p1.offset_from(p2) == 0 +}; +const OFFSET_ZERO: bool = unsafe { + let p = [0u8; 0].as_ptr(); + p.offset(0).offset_from(p) == 0 +}; +const OFFSET_ONE: bool = unsafe { + let p = &42u32 as *const u32; + p.offset(1).offset_from(p) == 1 +}; +const OFFSET_DANGLING: bool = unsafe { + let p = ptr::NonNull::::dangling().as_ptr(); + p.offset(0).offset_from(p) == 0 +}; +const OFFSET_UNALIGNED: bool = unsafe { + let arr = [0u8; 32]; + let p1 = arr.as_ptr(); + let p2 = (p1.offset(2) as *const u32).offset(1); + (p2 as *const u8).offset_from(p1) == 6 +}; + +const WRAP_OFFSET_NO_CHANGE: bool = unsafe { + let p1 = &42u32 as *const u32; + let p2 = p1.wrapping_offset(1000).wrapping_offset(-1000); + let p3 = p1.wrapping_offset(-1000).wrapping_offset(1000); + (p1.offset_from(p2) == 0) & (p1.offset_from(p3) == 0) +}; +const WRAP_ADDRESS_SPACE: bool = unsafe { + let p1 = &42u8 as *const u8; + let p2 = p1.wrapping_offset(isize::MIN).wrapping_offset(isize::MIN); + p1.offset_from(p2) == 0 +}; +// Wrap on the count*size_of::() calculation. +const WRAP_SIZE_OF: bool = unsafe { + // Make sure that if p1 moves backwards, we are still in range + let arr = [0u32; 2]; + let p = &arr[1] as *const u32; + // With wrapping arithmetic, isize::MAX * 4 == -4 + let wrapped = p.wrapping_offset(isize::MAX); + let backward = p.wrapping_offset(-1); + wrapped.offset_from(backward) == 0 +}; +const WRAP_INTEGER_POINTER: bool = unsafe { + let p1 = (0x42 as *const u32).wrapping_offset(4); + let p2 = 0x52 as *const u32; + p1.offset_from(p2) == 0 +}; +const WRAP_NULL: bool = unsafe { + let p1 = ptr::null::().wrapping_offset(1); + let p2 = 0x4 as *const u32; + p1.offset_from(p2) == 0 +}; + +fn main() { + assert!(OFFSET_NO_CHANGE); + assert!(OFFSET_MIDDLE); + assert!(OFFSET_END); + assert!(OFFSET_U8_PTR); + assert!(OFFSET_ZST); + assert!(OFFSET_ZERO); + assert!(OFFSET_ONE); + assert!(OFFSET_DANGLING); + assert!(OFFSET_UNALIGNED); + + assert!(WRAP_OFFSET_NO_CHANGE); + assert!(WRAP_ADDRESS_SPACE); + assert!(WRAP_SIZE_OF); + assert!(WRAP_INTEGER_POINTER); + assert!(WRAP_NULL); +} diff --git a/src/test/ui/consts/offset_ub.rs b/src/test/ui/consts/offset_ub.rs new file mode 100644 index 0000000000000..ac12078969480 --- /dev/null +++ b/src/test/ui/consts/offset_ub.rs @@ -0,0 +1,22 @@ +// ignore-tidy-linelength +#![feature(const_ptr_offset)] +use std::ptr; + +// normalize-stderr-test "alloc\d+" -> "allocN" + +pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; //~NOTE +pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; //~NOTE +pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; //~NOTE + +pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; //~NOTE +pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; //~NOTE +pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; //~NOTE +pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; //~NOTE + +pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~NOTE +pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; //~NOTE + +// Right now, a zero offset from null is UB +pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0) }; //~NOTE + +fn main() {} diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr new file mode 100644 index 0000000000000..b2b77586a504d --- /dev/null +++ b/src/test/ui/consts/offset_ub.stderr @@ -0,0 +1,154 @@ +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `BEFORE_START` at $DIR/offset_ub.rs:7:46 + | + ::: $DIR/offset_ub.rs:7:1 + | +LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; + | ------------------------------------------------------------------------------ + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `AFTER_END` at $DIR/offset_ub.rs:8:43 + | + ::: $DIR/offset_ub.rs:8:1 + | +LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; + | -------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45 + | + ::: $DIR/offset_ub.rs:9:1 + | +LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; + | ------------------------------------------------------------------------------ + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds pointer arithmetic: overflow computing offset + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `OVERFLOW` at $DIR/offset_ub.rs:11:43 + | + ::: $DIR/offset_ub.rs:11:1 + | +LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MAX) }; + | ---------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds pointer arithmetic: overflow computing offset + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44 + | + ::: $DIR/offset_ub.rs:12:1 + | +LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) }; + | ----------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56 + | + ::: $DIR/offset_ub.rs:13:1 + | +LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; + | --------------------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57 + | + ::: $DIR/offset_ub.rs:14:1 + | +LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; + | -------------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50 + | + ::: $DIR/offset_ub.rs:16:1 + | +LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; + | ------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) as *mut T + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn bytes into a pointer + | inside `std::ptr::mut_ptr::::offset` at $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL + | inside `DANGLING` at $DIR/offset_ub.rs:17:42 + | + ::: $DIR/offset_ub.rs:17:1 + | +LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; + | --------------------------------------------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: 0x0 is not a valid pointer + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50 + | + ::: $DIR/offset_ub.rs:20:1 + | +LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0) }; + | ------------------------------------------------------------------------------- + +error: aborting due to 10 previous errors + From 6b20f58c0d15500b2814a6f3579c29783463add0 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 18 May 2020 16:00:14 -0700 Subject: [PATCH 283/695] miri_unleached: We now allow offset in const fn Signed-off-by: Joe Richey --- .../ui/consts/miri_unleashed/ptr_arith.rs | 10 +-------- .../ui/consts/miri_unleashed/ptr_arith.stderr | 21 +++++-------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs index 81985f9f625a5..65fc49c0b27a6 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.rs +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs @@ -2,8 +2,7 @@ #![feature(core_intrinsics)] #![allow(const_err)] -// A test demonstrating that we prevent doing even trivial -// pointer arithmetic or comparison during CTFE. +// During CTFE, we prevent pointer comparison and pointer-to-int casts. static CMP: () = { let x = &0 as *const _; @@ -19,11 +18,4 @@ static INT_PTR_ARITH: () = unsafe { //~| NOTE pointer-to-integer cast }; -static PTR_ARITH: () = unsafe { - let x = &0 as *const _; - let _v = core::intrinsics::offset(x, 0); - //~^ ERROR could not evaluate static initializer - //~| NOTE calling intrinsic `offset` -}; - fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr index 5bd534a16b863..805ba9c6b0307 100644 --- a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr @@ -1,39 +1,28 @@ error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:10:14 + --> $DIR/ptr_arith.rs:9:14 | LL | let _v = x == x; | ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:17:14 + --> $DIR/ptr_arith.rs:16:14 | LL | let _v = x + 0; | ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants -error[E0080]: could not evaluate static initializer - --> $DIR/ptr_arith.rs:24:14 - | -LL | let _v = core::intrinsics::offset(x, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "calling intrinsic `offset`" needs an rfc before being allowed inside constants - warning: skipping const checks | help: skipping check for `const_compare_raw_pointers` feature - --> $DIR/ptr_arith.rs:10:14 + --> $DIR/ptr_arith.rs:9:14 | LL | let _v = x == x; | ^^^^^^ help: skipping check that does not even have a feature gate - --> $DIR/ptr_arith.rs:16:20 + --> $DIR/ptr_arith.rs:15:20 | LL | let x: usize = std::mem::transmute(&0); | ^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check that does not even have a feature gate - --> $DIR/ptr_arith.rs:24:14 - | -LL | let _v = core::intrinsics::offset(x, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. From 55577b411cd829b6793be8fd0af0e8811ba89e5c Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 25 May 2020 13:40:01 -0700 Subject: [PATCH 284/695] librustc_mir: Add back use statement Signed-off-by: Joe Richey --- src/librustc_mir/interpret/intrinsics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 0db9c7026588d..b474805926254 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -2,6 +2,8 @@ //! looking at their MIR. Intrinsics/functions supported here are shared by CTFE //! and miri. +use std::convert::TryFrom; + use rustc_hir::def_id::DefId; use rustc_middle::mir::{ self, From f2154e98379fcdd42ef226b6e19e9dc218422f83 Mon Sep 17 00:00:00 2001 From: returntrip Date: Mon, 25 May 2020 23:06:08 +0200 Subject: [PATCH 285/695] To make it easier for Linux distributions, ship the licenses text within each crate directory. --- rustc_tools_util/LICENSE-APACHE | 1 + rustc_tools_util/LICENSE-MIT | 1 + 2 files changed, 2 insertions(+) create mode 120000 rustc_tools_util/LICENSE-APACHE create mode 120000 rustc_tools_util/LICENSE-MIT diff --git a/rustc_tools_util/LICENSE-APACHE b/rustc_tools_util/LICENSE-APACHE new file mode 120000 index 0000000000000..965b606f331b5 --- /dev/null +++ b/rustc_tools_util/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/rustc_tools_util/LICENSE-MIT b/rustc_tools_util/LICENSE-MIT new file mode 120000 index 0000000000000..76219eb72e852 --- /dev/null +++ b/rustc_tools_util/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file From a1824e187cb6d17e48e2ff039810551540a9b826 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 25 May 2020 23:09:06 +0200 Subject: [PATCH 286/695] ptr_arg: honor `allow` attr on arguments --- clippy_lints/src/ptr.rs | 10 +++++++++- clippy_lints/src/utils/sugg.rs | 2 +- tests/ui/ptr_arg.rs | 32 +++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 2cdf96714195a..4eac571f96620 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -2,7 +2,7 @@ use crate::utils::ptr::get_spans; use crate::utils::{ - is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg, + is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg, span_lint_and_then, walk_ptrs_hir_ty, }; use if_chain::if_chain; @@ -150,8 +150,16 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_ let fn_def_id = cx.tcx.hir().local_def_id(fn_id); let sig = cx.tcx.fn_sig(fn_def_id); let fn_ty = sig.skip_binder(); + let body = opt_body_id.map(|id| cx.tcx.hir().body(id)); for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() { + // Honor the allow attribute on parameters. See issue 5644. + if let Some(body) = &body { + if is_allowed(cx, PTR_ARG, body.params[idx].hir_id) { + continue; + } + } + if let ty::Ref(_, ty, Mutability::Not) = ty.kind { if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { let mut ty_snippet = None; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 4ebe2e2852fb4..73758b7eeb7eb 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -530,7 +530,7 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext> { /// Suggest to add an item before another. /// - /// The item should not be indented (expect for inner indentation). + /// The item should not be indented (except for inner indentation). /// /// # Example /// diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 30f39e9b06398..541225e635102 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -71,7 +71,6 @@ fn false_positive_capacity_too(x: &String) -> String { #[allow(dead_code)] fn test_cow_with_ref(c: &Cow<[i32]>) {} -#[allow(dead_code)] fn test_cow(c: Cow<[i32]>) { let _c = c; } @@ -84,3 +83,34 @@ trait Foo2 { impl Foo2 for String { fn do_string(&self) {} } + +// Check that the allow attribute on parameters is honored +mod issue_5644 { + use std::borrow::Cow; + + fn allowed( + #[allow(clippy::ptr_arg)] _v: &Vec, + #[allow(clippy::ptr_arg)] _s: &String, + #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + ) { + } + + struct S {} + impl S { + fn allowed( + #[allow(clippy::ptr_arg)] _v: &Vec, + #[allow(clippy::ptr_arg)] _s: &String, + #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + ) { + } + } + + trait T { + fn allowed( + #[allow(clippy::ptr_arg)] _v: &Vec, + #[allow(clippy::ptr_arg)] _s: &String, + #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + ) { + } + } +} From c3dc8c455cee65db8928913da029725046c14a1b Mon Sep 17 00:00:00 2001 From: Dhruv Jauhar Date: Mon, 25 May 2020 12:57:47 -0700 Subject: [PATCH 287/695] Rename upvar_list to closure_captures As part of supporting RFC 2229, we will be capturing all the places that are mentioned in a closure. Currently the upvar_list field gives access to a FxIndexMap map. Eventually this will change, with the upvar_list having a more general structure that expresses captured paths, not just the mentioned upvars. We will make those changes in subsequent PRs. This commit modifies the name of the upvar_list map to closure_captures in TypeckTables. Co-authored-by: Dhruv Jauhar Co-authored-by: Aman Arora --- src/librustc_middle/ty/context.rs | 8 ++++---- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_mir/interpret/validity.rs | 2 +- src/librustc_mir_build/build/mod.rs | 4 ++-- src/librustc_mir_build/hair/cx/expr.rs | 2 +- src/librustc_typeck/check/upvar.rs | 8 ++++---- src/librustc_typeck/check/writeback.rs | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 5b53ab1778e3f..f2d1e6f42f615 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -419,7 +419,7 @@ pub struct TypeckTables<'tcx> { /// The upvarID contains the HIR node ID and it also contains the full path /// leading to the member of the struct or tuple that is used instead of the /// entire variable. - pub upvar_list: ty::UpvarListMap, + pub closure_captures: ty::UpvarListMap, /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). @@ -447,7 +447,7 @@ impl<'tcx> TypeckTables<'tcx> { used_trait_imports: Lrc::new(Default::default()), tainted_by_errors: None, concrete_opaque_types: Default::default(), - upvar_list: Default::default(), + closure_captures: Default::default(), generator_interior_types: Default::default(), } } @@ -688,7 +688,7 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { ref used_trait_imports, tainted_by_errors, ref concrete_opaque_types, - ref upvar_list, + ref closure_captures, ref generator_interior_types, } = *self; @@ -721,7 +721,7 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { used_trait_imports.hash_stable(hcx, hasher); tainted_by_errors.hash_stable(hcx, hasher); concrete_opaque_types.hash_stable(hcx, hasher); - upvar_list.hash_stable(hcx, hasher); + closure_captures.hash_stable(hcx, hasher); generator_interior_types.hash_stable(hcx, hasher); }) } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index a0c1d96bb4743..65e62dbd9dd49 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -142,7 +142,7 @@ fn do_mir_borrowck<'a, 'tcx>( infcx.set_tainted_by_errors(); } let upvars: Vec<_> = tables - .upvar_list + .closure_captures .get(&def_id.to_def_id()) .into_iter() .flat_map(|v| v.values()) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index c83555d65faf0..e962dfb2b3e86 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -227,7 +227,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let mut name = None; if let Some(def_id) = def_id.as_local() { let tables = self.ecx.tcx.typeck_tables_of(def_id); - if let Some(upvars) = tables.upvar_list.get(&def_id.to_def_id()) { + if let Some(upvars) = tables.closure_captures.get(&def_id.to_def_id()) { // Sometimes the index is beyond the number of upvars (seen // for a generator). if let Some((&var_hir_id, _)) = upvars.get_index(field) { diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index b30b57ea9217a..3d821aa55a1f8 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -790,11 +790,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let hir_tables = self.hir.tables(); // In analyze_closure() in upvar.rs we gathered a list of upvars used by a - // closure and we stored in a map called upvar_list in TypeckTables indexed + // indexed closure and we stored in a map called closure_captures in TypeckTables // with the closure's DefId. Here, we run through that vec of UpvarIds for // the given closure and use the necessary information to create upvar // debuginfo and to fill `self.upvar_mutbls`. - if let Some(upvars) = hir_tables.upvar_list.get(&fn_def_id) { + if let Some(upvars) = hir_tables.closure_captures.get(&fn_def_id) { let closure_env_arg = Local::new(1); let mut closure_env_projs = vec![]; let mut closure_ty = self.local_decls[closure_env_arg].ty; diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index 114bf5710402f..fd3c48b38badb 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -884,7 +884,7 @@ fn convert_var<'tcx>( ) -> ExprKind<'tcx> { let upvar_index = cx .tables() - .upvar_list + .closure_captures .get(&cx.body_owner) .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i)); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 8707e4fe84a22..19a23e5a59478 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { - let mut upvar_list: FxIndexMap = + let mut closure_captures: FxIndexMap = FxIndexMap::with_capacity_and_hasher(upvars.len(), Default::default()); for (&var_hir_id, _) in upvars.iter() { let upvar_id = ty::UpvarId { @@ -122,7 +122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("seed upvar_id {:?}", upvar_id); // Adding the upvar Id to the list of Upvars, which will be added // to the map for the closure at the end of the for loop. - upvar_list.insert(var_hir_id, upvar_id); + closure_captures.insert(var_hir_id, upvar_id); let capture_kind = match capture_clause { hir::CaptureBy::Value => ty::UpvarCapture::ByValue, @@ -140,8 +140,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Add the vector of upvars to the map keyed with the closure id. // This gives us an easier access to them without having to call // tcx.upvars again.. - if !upvar_list.is_empty() { - self.tables.borrow_mut().upvar_list.insert(closure_def_id, upvar_list); + if !closure_captures.is_empty() { + self.tables.borrow_mut().closure_captures.insert(closure_def_id, closure_captures); } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 154ca391aa5fd..3473dc7a58d04 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -74,8 +74,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.tables.used_trait_imports = used_trait_imports; - wbcx.tables.upvar_list = - mem::replace(&mut self.tables.borrow_mut().upvar_list, Default::default()); + wbcx.tables.closure_captures = + mem::replace(&mut self.tables.borrow_mut().closure_captures, Default::default()); if self.is_tainted_by_errors() { // FIXME(eddyb) keep track of `ErrorReported` from where the error was emitted. From 0fdbfd3f05cdca7cdbde839c34cdcdf040009e9e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 25 May 2020 17:17:27 -0700 Subject: [PATCH 288/695] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/embedded-book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 6247be15a7f75..e8a4714a9d8a6 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 6247be15a7f7509559f7981ee2209b9e0cc121df +Subproject commit e8a4714a9d8a6136a59b8e63544e149683876e36 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 49270740c7a4b..0a8ab50468297 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 49270740c7a4bff2763e6bc730b191d45b7d5167 +Subproject commit 0a8ab5046829733eb03df0738c4fafaa9b36b348 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 366c50a03bed9..5555a97f04ad7 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 366c50a03bed928589771eba8a6f18e0c0c01d23 +Subproject commit 5555a97f04ad7974ac6fb8fb47c267c4274adf4a diff --git a/src/doc/reference b/src/doc/reference index 892b928b565e3..becdca9477c9e 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 892b928b565e35d25b6f9c47faee03b94bc41489 +Subproject commit becdca9477c9eafa96a4eea5156fe7a2730d9dd2 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index ab072b14393cb..7aa82129aa23e 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit ab072b14393cbd9e8a1d1d75879bf51e27217bbb +Subproject commit 7aa82129aa23e7e181efbeb8da03a2a897ef6afc From a0431e26feeab88a178724520b73949b497070d3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 25 May 2020 17:56:32 -0700 Subject: [PATCH 289/695] Update cargo --- Cargo.lock | 24 +++++++++++++++++------- src/tools/cargo | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19ecd2023c639..5c0e3162e0d2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,7 +337,7 @@ dependencies = [ "rustc-workspace-hack", "rustfix", "same-file", - "semver", + "semver 0.10.0", "serde", "serde_ignored", "serde_json", @@ -389,7 +389,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "929766d993a2fde7a0ae962ee82429069cd7b68839cd9375b98efd719df65d3a" dependencies = [ "failure", - "semver", + "semver 0.9.0", "serde", "serde_derive", "serde_json", @@ -401,7 +401,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" dependencies = [ - "semver", + "semver 0.9.0", "serde", "serde_derive", "serde_json", @@ -540,7 +540,7 @@ dependencies = [ "lazy_static 1.4.0", "rustc-workspace-hack", "rustc_tools_util 0.2.0", - "semver", + "semver 0.9.0", "serde", "tempfile", "tester", @@ -561,7 +561,7 @@ dependencies = [ "pulldown-cmark 0.7.1", "quine-mc_cluskey", "regex-syntax", - "semver", + "semver 0.9.0", "serde", "smallvec 1.4.0", "toml", @@ -2090,7 +2090,7 @@ dependencies = [ "rayon", "regex", "reqwest", - "semver", + "semver 0.9.0", "serde", "serde_derive", "serde_json", @@ -4443,7 +4443,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", ] [[package]] @@ -4604,6 +4604,16 @@ dependencies = [ "serde", ] +[[package]] +name = "semver" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "394cec28fa623e00903caf7ba4fa6fb9a0e260280bb8cdbbba029611108a0190" +dependencies = [ + "semver-parser", + "serde", +] + [[package]] name = "semver-parser" version = "0.7.0" diff --git a/src/tools/cargo b/src/tools/cargo index 500b2bd01c958..9fcb8c1d20c17 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 500b2bd01c958f5a33b6aa3f080bea015877b83c +Subproject commit 9fcb8c1d20c17f51054f7aa4e08ff28d381fe096 From 66da7350963edf3d40461e6f5bafde95974908fc Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Tue, 26 May 2020 11:59:23 +0900 Subject: [PATCH 290/695] Add tracing issue for total_cmp --- src/libcore/num/f32.rs | 2 +- src/libcore/num/f64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index c54bfb27dfe5c..6313de31ce4d5 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -851,7 +851,7 @@ impl f32 { /// # .zip([-5.0, 0.1, 10.0, 99.0, f32::INFINITY, f32::NAN].iter()) /// # .all(|(a, b)| a.to_bits() == b.to_bits())) /// ``` - #[unstable(feature = "total_cmp", issue = "none")] + #[unstable(feature = "total_cmp", issue = "72599")] #[inline] pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { let mut left = self.to_bits() as i32; diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 18d5d720a0544..d42e5392c5863 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -865,7 +865,7 @@ impl f64 { /// # .zip([-5.0, 0.1, 10.0, 99.0, f64::INFINITY, f64::NAN].iter()) /// # .all(|(a, b)| a.to_bits() == b.to_bits())) /// ``` - #[unstable(feature = "total_cmp", issue = "none")] + #[unstable(feature = "total_cmp", issue = "72599")] #[inline] pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering { let mut left = self.to_bits() as i64; From 4e2696f54a449a366d2dae23bbc737947ec529ce Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 25 May 2020 15:53:41 -0400 Subject: [PATCH 291/695] Only capture tokens for items with outer attributes Suggested by @petrochenkov in https://github.com/rust-lang/rust/issues/43081#issuecomment-633389225 --- src/librustc_parse/parser/item.rs | 21 ++++++++++++++----- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 4fe0453e9c87f..6f13d7994d17d 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -106,11 +106,20 @@ impl<'a> Parser<'a> { }); let mut unclosed_delims = vec![]; - let (mut item, tokens) = self.collect_tokens(|this| { + let has_attrs = !attrs.is_empty(); + let parse_item = |this: &mut Self| { let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name); unclosed_delims.append(&mut this.unclosed_delims); item - })?; + }; + + let (mut item, tokens) = if has_attrs { + let (item, tokens) = self.collect_tokens(parse_item)?; + (item, Some(tokens)) + } else { + (parse_item(self)?, None) + }; + self.unclosed_delims.append(&mut unclosed_delims); // Once we've parsed an item and recorded the tokens we got while @@ -127,9 +136,11 @@ impl<'a> Parser<'a> { // it (bad!). To work around this case for now we just avoid recording // `tokens` if we detect any inner attributes. This should help keep // expansion correct, but we should fix this bug one day! - if let Some(item) = &mut item { - if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { - item.tokens = Some(tokens); + if let Some(tokens) = tokens { + if let Some(item) = &mut item { + if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { + item.tokens = Some(tokens); + } } } Ok(item) diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index f60b6a00be129..c7b0fbeb0e39b 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 42e7e78998063..59ed68c2a773f 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} From 1f0a3950797b2534e4f2106dd1b2e038eda4e3f5 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 26 May 2020 13:00:42 +0900 Subject: [PATCH 292/695] cargo update -p colored Updating colored v1.6.0 -> v1.9.3 Removing lazy_static v0.2.11 --- Cargo.lock | 98 ++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19ecd2023c639..4d51ed7d0684d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e266e1f4be5ffa05309f650e2586fe1d3ae6034eb24025a7ae1dfecc330823a" dependencies = [ "html5ever", - "lazy_static 1.4.0", + "lazy_static", "maplit", "matches", "tendril", @@ -210,7 +210,7 @@ dependencies = [ "filetime", "getopts", "ignore", - "lazy_static 1.4.0", + "lazy_static", "libc", "num_cpus", "opener", @@ -321,7 +321,7 @@ dependencies = [ "ignore", "im-rc", "jobserver", - "lazy_static 1.4.0", + "lazy_static", "lazycell", "libc", "libgit2-sys", @@ -375,7 +375,7 @@ dependencies = [ "flate2", "git2", "glob", - "lazy_static 1.4.0", + "lazy_static", "remove_dir_all", "serde_json", "tar", @@ -469,7 +469,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e4782d108e420a1fcf94d8a919cf248db33c5071678e87d9c2d4f20ed1feb32" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", ] [[package]] @@ -537,7 +537,7 @@ dependencies = [ "clippy_lints", "compiletest_rs", "derive-new", - "lazy_static 1.4.0", + "lazy_static", "rustc-workspace-hack", "rustc_tools_util 0.2.0", "semver", @@ -557,7 +557,7 @@ dependencies = [ "cargo_metadata 0.9.1", "if_chain", "itertools 0.9.0", - "lazy_static 1.4.0", + "lazy_static", "pulldown-cmark 0.7.1", "quine-mc_cluskey", "regex-syntax", @@ -609,11 +609,13 @@ dependencies = [ [[package]] name = "colored" -version = "1.6.0" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" dependencies = [ - "lazy_static 0.2.11", + "atty", + "lazy_static", + "winapi 0.3.8", ] [[package]] @@ -651,7 +653,7 @@ dependencies = [ "diff", "env_logger 0.7.1", "getopts", - "lazy_static 1.4.0", + "lazy_static", "libc", "log", "miow 0.3.3", @@ -808,7 +810,7 @@ dependencies = [ "arrayvec", "cfg-if", "crossbeam-utils 0.6.5", - "lazy_static 1.4.0", + "lazy_static", "memoffset", "scopeguard", ] @@ -829,7 +831,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" dependencies = [ "cfg-if", - "lazy_static 1.4.0", + "lazy_static", ] [[package]] @@ -840,7 +842,7 @@ checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg 1.0.0", "cfg-if", - "lazy_static 1.4.0", + "lazy_static", ] [[package]] @@ -1046,7 +1048,7 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a99a310cd1f9770e7bf8e48810c7bcbb0e078c8fb23a8c7bcf0da4c2bf61a455" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "regex", "serde", "serde_derive", @@ -1614,7 +1616,7 @@ checksum = "522daefc3b69036f80c7d2990b28ff9e0471c683bad05ca258e0a01dd22c5a1e" dependencies = [ "crossbeam-channel", "globset", - "lazy_static 1.4.0", + "lazy_static", "log", "memchr", "regex", @@ -1651,7 +1653,7 @@ dependencies = [ "clap", "failure", "flate2", - "lazy_static 1.4.0", + "lazy_static", "num_cpus", "rayon", "remove_dir_all", @@ -1823,7 +1825,7 @@ dependencies = [ "bytes", "globset", "jsonrpc-core", - "lazy_static 1.4.0", + "lazy_static", "log", "tokio", "tokio-codec", @@ -1840,12 +1842,6 @@ dependencies = [ "winapi-build", ] -[[package]] -name = "lazy_static" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" - [[package]] name = "lazy_static" version = "1.4.0" @@ -1951,7 +1947,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", ] [[package]] @@ -2055,7 +2051,7 @@ dependencies = [ "error-chain", "handlebars", "itertools 0.8.0", - "lazy_static 1.4.0", + "lazy_static", "log", "memchr", "open", @@ -2264,7 +2260,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "libc", "log", "openssl", @@ -2362,7 +2358,7 @@ dependencies = [ "bitflags", "cfg-if", "foreign-types", - "lazy_static 1.4.0", + "lazy_static", "libc", "openssl-sys", ] @@ -2740,7 +2736,7 @@ checksum = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510" dependencies = [ "error-chain", "idna 0.2.0", - "lazy_static 1.4.0", + "lazy_static", "regex", "url 2.1.0", ] @@ -2815,7 +2811,7 @@ dependencies = [ "derive_more", "env_logger 0.7.1", "humantime 2.0.0", - "lazy_static 1.4.0", + "lazy_static", "log", "rls-span", "rustc-ap-rustc_ast", @@ -2998,7 +2994,7 @@ dependencies = [ "crossbeam-deque", "crossbeam-queue", "crossbeam-utils 0.6.5", - "lazy_static 1.4.0", + "lazy_static", "num_cpus", ] @@ -3127,7 +3123,7 @@ dependencies = [ "home", "itertools 0.8.0", "jsonrpc-core", - "lazy_static 1.4.0", + "lazy_static", "log", "lsp-codec", "lsp-types", @@ -3339,7 +3335,7 @@ dependencies = [ "ena 0.13.1", "indexmap", "jobserver", - "lazy_static 1.4.0", + "lazy_static", "libc", "log", "measureme", @@ -3401,7 +3397,7 @@ version = "654.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96fb53e1710e6de7c2e371ca56c857b79f9b399aba58aa6b6fbed6e2f677d3f6" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_span", ] @@ -3575,7 +3571,7 @@ dependencies = [ "crossbeam-deque", "crossbeam-queue", "crossbeam-utils 0.6.5", - "lazy_static 1.4.0", + "lazy_static", "num_cpus", ] @@ -3791,7 +3787,7 @@ dependencies = [ "graphviz", "indexmap", "jobserver", - "lazy_static 1.4.0", + "lazy_static", "libc", "log", "measureme", @@ -3813,7 +3809,7 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "env_logger 0.7.1", - "lazy_static 1.4.0", + "lazy_static", "libc", "log", "rustc_ast", @@ -3884,7 +3880,7 @@ dependencies = [ name = "rustc_feature" version = "0.0.0" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "rustc_data_structures", "rustc_span", ] @@ -3897,7 +3893,7 @@ version = "0.0.0" name = "rustc_hir" version = "0.0.0" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "log", "rustc_ast", "rustc_data_structures", @@ -4507,7 +4503,7 @@ dependencies = [ "getopts", "ignore", "itertools 0.8.0", - "lazy_static 1.4.0", + "lazy_static", "log", "regex", "rustc-ap-rustc_ast", @@ -4551,7 +4547,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "winapi 0.3.8", ] @@ -4817,7 +4813,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "new_debug_unreachable", "phf_shared", "precomputed-hash", @@ -5081,7 +5077,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", ] [[package]] @@ -5090,7 +5086,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", ] [[package]] @@ -5098,7 +5094,7 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo_metadata 0.9.1", - "lazy_static 1.4.0", + "lazy_static", "regex", "walkdir", ] @@ -5223,7 +5219,7 @@ checksum = "afbd6ef1b8cc2bd2c2b580d882774d443ebb1c6ceefe35ba9ea4ab586c89dbe8" dependencies = [ "crossbeam-queue", "futures", - "lazy_static 1.4.0", + "lazy_static", "libc", "log", "mio", @@ -5242,7 +5238,7 @@ checksum = "6732fe6b53c8d11178dcb77ac6d9682af27fc6d4cb87789449152e5377377146" dependencies = [ "crossbeam-utils 0.6.5", "futures", - "lazy_static 1.4.0", + "lazy_static", "log", "mio", "num_cpus", @@ -5313,7 +5309,7 @@ dependencies = [ "crossbeam-queue", "crossbeam-utils 0.6.5", "futures", - "lazy_static 1.4.0", + "lazy_static", "log", "num_cpus", "slab", @@ -5383,7 +5379,7 @@ dependencies = [ "failure", "failure_derive", "is-match", - "lazy_static 1.4.0", + "lazy_static", "regex", "toml", "toml-query_derive", @@ -5427,7 +5423,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6b52bf4da6512f0f07785a04769222e50d29639e7ecd016b7806fd2de306b4" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "regex", ] @@ -5764,7 +5760,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59893318ba3ad2b704498c7761214a10eaf42c5f838bce9fc0145bf2ba658cfa" dependencies = [ - "lazy_static 1.4.0", + "lazy_static", "thiserror", "yaml-rust 0.4.3", ] From b4b76b8206442b27514ab577351084f15d28906e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 26 May 2020 13:04:59 +0900 Subject: [PATCH 293/695] cargo update -p regex --aggressive Updating aho-corasick v0.7.3 -> v0.7.10 Updating memchr v2.3.2 -> v2.3.3 Updating regex v1.1.6 -> v1.3.7 Updating regex-syntax v0.6.6 -> v0.6.17 Removing thread_local v0.3.6 Removing ucd-util v0.1.3 Removing utf8-ranges v1.0.2 --- Cargo.lock | 45 ++++++++++----------------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d51ed7d0684d..5f13a0a5bf846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,9 +8,9 @@ checksum = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" [[package]] name = "aho-corasick" -version = "0.7.3" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" dependencies = [ "memchr", ] @@ -1621,7 +1621,7 @@ dependencies = [ "memchr", "regex", "same-file", - "thread_local 1.0.1", + "thread_local", "walkdir", "winapi-util", ] @@ -2107,9 +2107,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "memmap" @@ -3036,25 +3036,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.1.6" +version = "1.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" +checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local 0.3.6", - "utf8-ranges", + "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.6" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" -dependencies = [ - "ucd-util", -] +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" [[package]] name = "remote-test-client" @@ -5071,15 +5067,6 @@ dependencies = [ "syn 1.0.11", ] -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -dependencies = [ - "lazy_static", -] - [[package]] name = "thread_local" version = "1.0.1" @@ -5433,12 +5420,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77" -[[package]] -name = "ucd-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" - [[package]] name = "unicase" version = "2.6.0" @@ -5572,12 +5553,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c" -[[package]] -name = "utf8-ranges" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" - [[package]] name = "utf8parse" version = "0.1.1" From a6e58ae3ce78c4a089465d1666b659d1ec8257ca Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 26 May 2020 13:33:06 +0900 Subject: [PATCH 294/695] cargo update -p rls-analysis Removing itertools v0.7.8 Updating rls-analysis v0.18.0 -> v0.18.1 Updating rls-span v0.5.1 -> v0.5.2 --- Cargo.lock | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f13a0a5bf846..71bfba0a8b2eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1678,15 +1678,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" -[[package]] -name = "itertools" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.8.0" @@ -3153,13 +3144,13 @@ dependencies = [ [[package]] name = "rls-analysis" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0d208ad66717501222c74b42d9e823a7612592e85ed78b04074c8f58c0be0a" +checksum = "534032993e1b60e5db934eab2dde54da7afd1e46c3465fddb2b29eb47cb1ed3a" dependencies = [ "derive-new", "fst", - "itertools 0.7.8", + "itertools 0.8.0", "json", "log", "rls-data", @@ -3207,9 +3198,9 @@ dependencies = [ [[package]] name = "rls-span" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1cb4694410d8d2ce43ccff3682f1c782158a018d5a9a92185675677f7533eb3" +checksum = "f2e9bed56f6272bd85d9d06d1aaeef80c5fddc78a82199eb36dceb5f94e7d934" dependencies = [ "serde", ] From 9f8628b38ce8960d4ef46ea60c3c0fcca2ca259d Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 26 May 2020 13:35:21 +0900 Subject: [PATCH 295/695] cargo update -p atty --aggressive Updating atty v0.2.11 -> v0.2.14 Removing c2-chacha v0.2.3 Updating cc v1.0.52 -> v1.0.54 Updating ppv-lite86 v0.2.6 -> v0.2.8 Updating rand_chacha v0.2.1 -> v0.2.2 Removing redox_termios v0.1.1 Removing termion v1.5.1 --- Cargo.lock | 51 +++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 71bfba0a8b2eb..66e93483d8eff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,12 +98,12 @@ dependencies = [ [[package]] name = "atty" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ + "hermit-abi", "libc", - "termion", "winapi 0.3.8", ] @@ -282,15 +282,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" -[[package]] -name = "c2-chacha" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -dependencies = [ - "ppv-lite86", -] - [[package]] name = "cargo" version = "0.46.0" @@ -413,9 +404,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.52" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" +checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" dependencies = [ "jobserver", ] @@ -2624,9 +2615,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" [[package]] name = "precomputed-hash" @@ -2841,7 +2832,7 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom", "libc", - "rand_chacha 0.2.1", + "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc 0.2.0", ] @@ -2858,11 +2849,11 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "c2-chacha", + "ppv-lite86", "rand_core 0.5.1", ] @@ -3004,15 +2995,6 @@ version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -dependencies = [ - "redox_syscall", -] - [[package]] name = "redox_users" version = "0.3.0" @@ -4983,17 +4965,6 @@ dependencies = [ "wincolor", ] -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -dependencies = [ - "libc", - "redox_syscall", - "redox_termios", -] - [[package]] name = "termize" version = "0.1.1" From ffa493ab57fbb44f16efae2515abdde6876cc5c9 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sun, 17 May 2020 01:48:01 -0700 Subject: [PATCH 296/695] Implement warning for unused dependencies. This will print a diagnostic for crates which are mentioned as `--extern` arguments on the command line, but are never referenced from the source. This diagnostic is controlled by `-Wunused-crate-dependencies` or `#![warn(unused_crate_dependencies)]` and is "allow" by default. There are cases where certain crates need to be linked in but are not directly referenced - for example if they are providing symbols for C linkage. In this case the warning can be suppressed with `use needed_crate as _;`. Thanks to @petrochenkov for simplified core. Resolves issue #57274 --- src/librustc_lint/lib.rs | 1 + src/librustc_metadata/creader.rs | 29 +++++++++++++++++++ src/librustc_session/lint/builtin.rs | 7 +++++ .../ui/unused-crate-deps/auxiliary/bar.rs | 1 + .../ui/unused-crate-deps/auxiliary/foo.rs | 5 ++++ src/test/ui/unused-crate-deps/libfib.rs | 21 ++++++++++++++ src/test/ui/unused-crate-deps/libfib.stderr | 10 +++++++ src/test/ui/unused-crate-deps/suppress.rs | 11 +++++++ .../ui/unused-crate-deps/unused-aliases.rs | 13 +++++++++ .../unused-crate-deps/unused-aliases.stderr | 14 +++++++++ .../use_extern_crate_2015.rs | 13 +++++++++ src/test/ui/unused-crate-deps/warn-attr.rs | 10 +++++++ .../ui/unused-crate-deps/warn-attr.stderr | 14 +++++++++ .../unused-crate-deps/warn-cmdline-static.rs | 10 +++++++ .../warn-cmdline-static.stderr | 10 +++++++ src/test/ui/unused-crate-deps/warn-cmdline.rs | 9 ++++++ .../ui/unused-crate-deps/warn-cmdline.stderr | 10 +++++++ 17 files changed, 188 insertions(+) create mode 100644 src/test/ui/unused-crate-deps/auxiliary/bar.rs create mode 100644 src/test/ui/unused-crate-deps/auxiliary/foo.rs create mode 100644 src/test/ui/unused-crate-deps/libfib.rs create mode 100644 src/test/ui/unused-crate-deps/libfib.stderr create mode 100644 src/test/ui/unused-crate-deps/suppress.rs create mode 100644 src/test/ui/unused-crate-deps/unused-aliases.rs create mode 100644 src/test/ui/unused-crate-deps/unused-aliases.stderr create mode 100644 src/test/ui/unused-crate-deps/use_extern_crate_2015.rs create mode 100644 src/test/ui/unused-crate-deps/warn-attr.rs create mode 100644 src/test/ui/unused-crate-deps/warn-attr.stderr create mode 100644 src/test/ui/unused-crate-deps/warn-cmdline-static.rs create mode 100644 src/test/ui/unused-crate-deps/warn-cmdline-static.stderr create mode 100644 src/test/ui/unused-crate-deps/warn-cmdline.rs create mode 100644 src/test/ui/unused-crate-deps/warn-cmdline.stderr diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index b791d313fc4f4..ee27342541c93 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -276,6 +276,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { UNUSED_ALLOCATION, UNUSED_DOC_COMMENTS, UNUSED_EXTERN_CRATES, + UNUSED_CRATE_DEPENDENCIES, UNUSED_FEATURES, UNUSED_LABELS, UNUSED_PARENS, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index b0220ddd3c38e..db29e9538999a 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -5,6 +5,7 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob use rustc_ast::expand::allocator::{global_allocator_spans, AllocatorKind}; use rustc_ast::{ast, attr}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; @@ -18,6 +19,7 @@ use rustc_middle::middle::cstore::{ }; use rustc_middle::ty::TyCtxt; use rustc_session::config::{self, CrateType}; +use rustc_session::lint; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_session::{CrateDisambiguator, Session}; @@ -49,6 +51,7 @@ pub struct CrateLoader<'a> { local_crate_name: Symbol, // Mutable output. cstore: CStore, + used_extern_options: FxHashSet, } pub enum LoadedMacro { @@ -205,6 +208,7 @@ impl<'a> CrateLoader<'a> { allocator_kind: None, has_global_allocator: false, }, + used_extern_options: Default::default(), } } @@ -445,6 +449,9 @@ impl<'a> CrateLoader<'a> { dep_kind: DepKind, dep: Option<(&'b CratePaths, &'b CrateDep)>, ) -> CrateNum { + if dep.is_none() { + self.used_extern_options.insert(name); + } self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report()) } @@ -839,6 +846,26 @@ impl<'a> CrateLoader<'a> { }); } + fn report_unused_deps(&mut self, krate: &ast::Crate) { + // Make a point span rather than covering the whole file + let span = krate.span.shrink_to_lo(); + // Complain about anything left over + for (name, _) in self.sess.opts.externs.iter() { + if !self.used_extern_options.contains(&Symbol::intern(name)) { + self.sess.parse_sess.buffer_lint( + lint::builtin::UNUSED_CRATE_DEPENDENCIES, + span, + ast::CRATE_NODE_ID, + &format!( + "external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`", + name, + self.local_crate_name, + name), + ); + } + } + } + pub fn postprocess(&mut self, krate: &ast::Crate) { self.inject_profiler_runtime(); self.inject_allocator_crate(krate); @@ -847,6 +874,8 @@ impl<'a> CrateLoader<'a> { if log_enabled!(log::Level::Info) { dump_crates(&self.cstore); } + + self.report_unused_deps(krate); } pub fn process_extern_crate( diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 3d03e46683ed5..66d8908799181 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -71,6 +71,12 @@ declare_lint! { "extern crates that are never used" } +declare_lint! { + pub UNUSED_CRATE_DEPENDENCIES, + Allow, + "crate dependencies that are never used" +} + declare_lint! { pub UNUSED_QUALIFICATIONS, Allow, @@ -523,6 +529,7 @@ declare_lint_pass! { UNCONDITIONAL_PANIC, UNUSED_IMPORTS, UNUSED_EXTERN_CRATES, + UNUSED_CRATE_DEPENDENCIES, UNUSED_QUALIFICATIONS, UNKNOWN_LINTS, UNUSED_VARIABLES, diff --git a/src/test/ui/unused-crate-deps/auxiliary/bar.rs b/src/test/ui/unused-crate-deps/auxiliary/bar.rs new file mode 100644 index 0000000000000..1d3824e7a44f6 --- /dev/null +++ b/src/test/ui/unused-crate-deps/auxiliary/bar.rs @@ -0,0 +1 @@ +pub const BAR: &str = "bar"; diff --git a/src/test/ui/unused-crate-deps/auxiliary/foo.rs b/src/test/ui/unused-crate-deps/auxiliary/foo.rs new file mode 100644 index 0000000000000..0ef03eb9edf0f --- /dev/null +++ b/src/test/ui/unused-crate-deps/auxiliary/foo.rs @@ -0,0 +1,5 @@ +// edition:2018 +// aux-crate:bar=bar.rs + +pub const FOO: &str = "foo"; +pub use bar::BAR; diff --git a/src/test/ui/unused-crate-deps/libfib.rs b/src/test/ui/unused-crate-deps/libfib.rs new file mode 100644 index 0000000000000..c1545dca99f57 --- /dev/null +++ b/src/test/ui/unused-crate-deps/libfib.rs @@ -0,0 +1,21 @@ +// Test warnings for a library crate + +// check-pass +// aux-crate:bar=bar.rs +// compile-flags:--crate-type lib -Wunused-crate-dependencies + +pub fn fib(n: u32) -> Vec { +//~^ WARNING external crate `bar` unused in +let mut prev = 0; + let mut cur = 1; + let mut v = vec![]; + + for _ in 0..n { + v.push(prev); + let n = prev + cur; + prev = cur; + cur = n; + } + + v +} diff --git a/src/test/ui/unused-crate-deps/libfib.stderr b/src/test/ui/unused-crate-deps/libfib.stderr new file mode 100644 index 0000000000000..15833126bd620 --- /dev/null +++ b/src/test/ui/unused-crate-deps/libfib.stderr @@ -0,0 +1,10 @@ +warning: external crate `bar` unused in `libfib`: remove the dependency or add `use bar as _;` + --> $DIR/libfib.rs:7:1 + | +LL | pub fn fib(n: u32) -> Vec { + | ^ + | + = note: requested on the command line with `-W unused-crate-dependencies` + +warning: 1 warning emitted + diff --git a/src/test/ui/unused-crate-deps/suppress.rs b/src/test/ui/unused-crate-deps/suppress.rs new file mode 100644 index 0000000000000..8904d04bc14f7 --- /dev/null +++ b/src/test/ui/unused-crate-deps/suppress.rs @@ -0,0 +1,11 @@ +// Suppress by using crate + +// edition:2018 +// check-pass +// aux-crate:bar=bar.rs + +#![warn(unused_crate_dependencies)] + +use bar as _; + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/unused-aliases.rs b/src/test/ui/unused-crate-deps/unused-aliases.rs new file mode 100644 index 0000000000000..1b7cb9b970e49 --- /dev/null +++ b/src/test/ui/unused-crate-deps/unused-aliases.rs @@ -0,0 +1,13 @@ +// Warn about unused aliased for the crate + +// edition:2018 +// check-pass +// aux-crate:bar=bar.rs +// aux-crate:barbar=bar.rs + +#![warn(unused_crate_dependencies)] +//~^ WARNING external crate `barbar` unused in + +use bar as _; + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/unused-aliases.stderr b/src/test/ui/unused-crate-deps/unused-aliases.stderr new file mode 100644 index 0000000000000..c8c6c4507b0c5 --- /dev/null +++ b/src/test/ui/unused-crate-deps/unused-aliases.stderr @@ -0,0 +1,14 @@ +warning: external crate `barbar` unused in `unused_aliases`: remove the dependency or add `use barbar as _;` + --> $DIR/unused-aliases.rs:8:1 + | +LL | #![warn(unused_crate_dependencies)] + | ^ + | +note: the lint level is defined here + --> $DIR/unused-aliases.rs:8:9 + | +LL | #![warn(unused_crate_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/src/test/ui/unused-crate-deps/use_extern_crate_2015.rs b/src/test/ui/unused-crate-deps/use_extern_crate_2015.rs new file mode 100644 index 0000000000000..f15c87fa0b249 --- /dev/null +++ b/src/test/ui/unused-crate-deps/use_extern_crate_2015.rs @@ -0,0 +1,13 @@ +// Suppress by using crate + +// edition:2015 +// check-pass +// aux-crate:bar=bar.rs + +#![warn(unused_crate_dependencies)] + +extern crate bar; + +fn main() { + println!("bar {}", bar::BAR); +} diff --git a/src/test/ui/unused-crate-deps/warn-attr.rs b/src/test/ui/unused-crate-deps/warn-attr.rs new file mode 100644 index 0000000000000..1acb307ab21b3 --- /dev/null +++ b/src/test/ui/unused-crate-deps/warn-attr.rs @@ -0,0 +1,10 @@ +// Check for unused crate dep, no path + +// edition:2018 +// check-pass +// aux-crate:bar=bar.rs + +#![warn(unused_crate_dependencies)] +//~^ WARNING external crate `bar` unused in + +fn main() {} diff --git a/src/test/ui/unused-crate-deps/warn-attr.stderr b/src/test/ui/unused-crate-deps/warn-attr.stderr new file mode 100644 index 0000000000000..0d38315704b11 --- /dev/null +++ b/src/test/ui/unused-crate-deps/warn-attr.stderr @@ -0,0 +1,14 @@ +warning: external crate `bar` unused in `warn_attr`: remove the dependency or add `use bar as _;` + --> $DIR/warn-attr.rs:7:1 + | +LL | #![warn(unused_crate_dependencies)] + | ^ + | +note: the lint level is defined here + --> $DIR/warn-attr.rs:7:9 + | +LL | #![warn(unused_crate_dependencies)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/src/test/ui/unused-crate-deps/warn-cmdline-static.rs b/src/test/ui/unused-crate-deps/warn-cmdline-static.rs new file mode 100644 index 0000000000000..c609529a6c6fb --- /dev/null +++ b/src/test/ui/unused-crate-deps/warn-cmdline-static.rs @@ -0,0 +1,10 @@ +// Check for unused crate dep, no path + +// edition:2018 +// check-pass +// compile-flags: -Wunused-crate-dependencies +// aux-crate:bar=bar.rs +// no-prefer-dynamic + +fn main() {} +//~^ WARNING external crate `bar` unused in diff --git a/src/test/ui/unused-crate-deps/warn-cmdline-static.stderr b/src/test/ui/unused-crate-deps/warn-cmdline-static.stderr new file mode 100644 index 0000000000000..65956461d6439 --- /dev/null +++ b/src/test/ui/unused-crate-deps/warn-cmdline-static.stderr @@ -0,0 +1,10 @@ +warning: external crate `bar` unused in `warn_cmdline_static`: remove the dependency or add `use bar as _;` + --> $DIR/warn-cmdline-static.rs:9:1 + | +LL | fn main() {} + | ^ + | + = note: requested on the command line with `-W unused-crate-dependencies` + +warning: 1 warning emitted + diff --git a/src/test/ui/unused-crate-deps/warn-cmdline.rs b/src/test/ui/unused-crate-deps/warn-cmdline.rs new file mode 100644 index 0000000000000..3bae61c3ea2cc --- /dev/null +++ b/src/test/ui/unused-crate-deps/warn-cmdline.rs @@ -0,0 +1,9 @@ +// Check for unused crate dep, no path + +// edition:2018 +// check-pass +// compile-flags: -Wunused-crate-dependencies +// aux-crate:bar=bar.rs + +fn main() {} +//~^ WARNING external crate `bar` unused in diff --git a/src/test/ui/unused-crate-deps/warn-cmdline.stderr b/src/test/ui/unused-crate-deps/warn-cmdline.stderr new file mode 100644 index 0000000000000..ea675ba9a1eb1 --- /dev/null +++ b/src/test/ui/unused-crate-deps/warn-cmdline.stderr @@ -0,0 +1,10 @@ +warning: external crate `bar` unused in `warn_cmdline`: remove the dependency or add `use bar as _;` + --> $DIR/warn-cmdline.rs:8:1 + | +LL | fn main() {} + | ^ + | + = note: requested on the command line with `-W unused-crate-dependencies` + +warning: 1 warning emitted + From 3d4f4787a6b4d752434faa8be34c01fa024653bb Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 26 May 2020 16:38:09 +0900 Subject: [PATCH 297/695] Update allowed crates list --- src/tools/tidy/src/deps.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 61389028cc78c..c08f02b972e8f 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -77,7 +77,6 @@ const WHITELIST: &[&str] = &[ "block-padding", "byte-tools", "byteorder", - "c2-chacha", "cc", "cfg-if", "chalk-derive", @@ -148,7 +147,6 @@ const WHITELIST: &[&str] = &[ "rand_pcg", "rand_xorshift", "redox_syscall", - "redox_termios", "regex", "regex-syntax", "remove_dir_all", @@ -171,17 +169,14 @@ const WHITELIST: &[&str] = &[ "synstructure", "tempfile", "termcolor", - "termion", "termize", "thread_local", "typenum", - "ucd-util", "unicode-normalization", "unicode-script", "unicode-security", "unicode-width", "unicode-xid", - "utf8-ranges", "vcpkg", "version_check", "wasi", From b9ba4b3810a4f818d2a1e4eb5b17841bd799e519 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 May 2020 10:47:54 +0200 Subject: [PATCH 298/695] Small cell example update --- src/libcore/cell.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 0f2665eba6f22..40a4fb50c9970 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -850,11 +850,11 @@ impl RefCell { /// ``` /// use std::cell::RefCell; /// - /// let c = RefCell::new(5); + /// let c = RefCell::new("hello".to_owned()); /// - /// *c.borrow_mut() = 7; + /// *c.borrow_mut() = "bonjour".to_owned(); /// - /// assert_eq!(*c.borrow(), 7); + /// assert_eq!(&*c.borrow(), "bonjour"); /// ``` /// /// An example of panic: From 6367b544b781889abee296d34d2b7d353a6ae0f8 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 26 May 2020 01:57:49 -0700 Subject: [PATCH 299/695] librustc_middle: Add function for computing unsigned abs This is tricky to get right if we want to avoid panicking or wrapping. Signed-off-by: Joe Richey --- src/librustc_middle/mir/interpret/mod.rs | 9 +++++++++ src/librustc_middle/mir/interpret/pointer.rs | 13 +++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs index d9e52af89007c..061bc9750e1c2 100644 --- a/src/librustc_middle/mir/interpret/mod.rs +++ b/src/librustc_middle/mir/interpret/mod.rs @@ -598,3 +598,12 @@ pub fn truncate(value: u128, size: Size) -> u128 { // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). (value << shift) >> shift } + +/// Computes the unsigned absolute value without wrapping or panicking. +#[inline] +pub fn uabs(value: i64) -> u64 { + // The only tricky part here is if value == i64::MIN. In that case, + // wrapping_abs() returns i64::MIN == -2^63. Casting this value to a u64 + // gives 2^63, the correct value. + value.wrapping_abs() as u64 +} diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/src/librustc_middle/mir/interpret/pointer.rs index 70cc546199b79..019c96bc511eb 100644 --- a/src/librustc_middle/mir/interpret/pointer.rs +++ b/src/librustc_middle/mir/interpret/pointer.rs @@ -1,4 +1,4 @@ -use super::{AllocId, InterpResult}; +use super::{uabs, AllocId, InterpResult}; use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size}; @@ -48,15 +48,12 @@ pub trait PointerArithmetic: HasDataLayout { #[inline] fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) { - if i < 0 { - // Trickery to ensure that `i64::MIN` works fine: compute `n = -i`. - // This formula only works for true negative values; it overflows for zero! - let n = u64::MAX - (i as u64) + 1; + let n = uabs(i); + if i >= 0 { + self.overflowing_offset(val, n) + } else { let res = val.overflowing_sub(n); self.truncate_to_ptr(res) - } else { - // `i >= 0`, so the cast is safe. - self.overflowing_offset(val, i as u64) } } From 71ef8414bd86cbd79b29f8b1a0145da96e2f2f09 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 26 May 2020 02:00:02 -0700 Subject: [PATCH 300/695] Add checks and tests for computing abs(offset_bytes) The previous code paniced if offset_bytes == i64::MIN. This commit: - Properly computes the absoulte value to avoid this panic - Adds a test for this edge case Signed-off-by: Joe Richey --- src/librustc_mir/interpret/intrinsics.rs | 5 +++-- src/test/ui/consts/offset_ub.rs | 3 +++ src/test/ui/consts/offset_ub.stderr | 17 ++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index b474805926254..239115076bc4b 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -7,7 +7,7 @@ use std::convert::TryFrom; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ self, - interpret::{ConstValue, GlobalId, InterpResult, Scalar}, + interpret::{uabs, ConstValue, GlobalId, InterpResult, Scalar}, BinOp, }; use rustc_middle::ty; @@ -438,6 +438,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pointee_ty: Ty<'tcx>, offset_count: i64, ) -> InterpResult<'tcx, Scalar> { + // We cannot overflow i64 as a type's size must be <= isize::MAX. let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); // The computed offset, in bytes, cannot overflow an isize. let offset_bytes = offset_count @@ -450,7 +451,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // memory between these pointers must be accessible. Note that we do not require the // pointers to be properly aligned (unlike a read/write operation). let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; - let size = offset_bytes.checked_abs().unwrap(); + let size: u64 = uabs(offset_bytes); // This call handles checking for integer/NULL pointers. self.memory.check_ptr_access_align( min_ptr, diff --git a/src/test/ui/consts/offset_ub.rs b/src/test/ui/consts/offset_ub.rs index ac12078969480..4f943ed9ad194 100644 --- a/src/test/ui/consts/offset_ub.rs +++ b/src/test/ui/consts/offset_ub.rs @@ -19,4 +19,7 @@ pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr() // Right now, a zero offset from null is UB pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0) }; //~NOTE +// Make sure that we don't panic when computing abs(offset*size_of::()) +pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; //~NOTE + fn main() {} diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index b2b77586a504d..e808939682f30 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -150,5 +150,20 @@ LL | intrinsics::offset(self, count) LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0) }; | ------------------------------------------------------------------------------- -error: aborting due to 10 previous errors +error: any use of this value will cause an error + --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | +LL | intrinsics::offset(self, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn bytes into a pointer + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:23:47 + | + ::: $DIR/offset_ub.rs:23:1 + | +LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; + | --------------------------------------------------------------------------------------------- + +error: aborting due to 11 previous errors From 37bdb3bb3b4323733f8ecdd4925ca314133c6fd0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 May 2020 11:16:02 +0200 Subject: [PATCH 301/695] Update UI test --- src/test/ui/json-short.stderr | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json-short.stderr index 60c2582b11eae..3bd85b083d002 100644 --- a/src/test/ui/json-short.stderr +++ b/src/test/ui/json-short.stderr @@ -1,5 +1,6 @@ -{"message":"`main` function not found in crate `json_short`","code":{"code":"E0601","explanation":"No `main` function was found in a binary crate. To fix this error, add a -`main` function. For example: +{"message":"`main` function not found in crate `json_short`","code":{"code":"E0601","explanation":"No `main` function was found in a binary crate. + +To fix this error, add a `main` function: ``` fn main() { From 0fa4762a807a8e637aeaa805bc705c52a1c70d13 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 17 May 2020 14:06:21 +0200 Subject: [PATCH 302/695] Move focusSearchBar and defocusSearchBar functions to the top of the file with other functions --- src/librustdoc/html/static/main.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 9869c50fbb0cf..94d74bf793e7c 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -47,6 +47,17 @@ function getSearchElement() { return document.getElementById("search"); } +// Sets the focus on the search bar at the top of the page +function focusSearchBar() { + getSearchInput().focus(); +} + +// Removes the focus from the search bar +function defocusSearchBar() { + getSearchInput().blur(); +} + + (function() { "use strict"; @@ -2778,16 +2789,6 @@ function getSearchElement() { buildHelperPopup(); }()); -// Sets the focus on the search bar at the top of the page -function focusSearchBar() { - getSearchInput().focus(); -} - -// Removes the focus from the search bar -function defocusSearchBar() { - getSearchInput().blur(); -} - // This is required in firefox. Explanations: when going back in the history, firefox doesn't re-run // the JS, therefore preventing rustdoc from setting a few things required to be able to reload the // previous search results (if you navigated to a search result with the keyboard, pressed enter on From deaf5e200e79a75ac57d3f0952f6758a38168e52 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 17 May 2020 14:49:04 +0200 Subject: [PATCH 303/695] Move "global" code into anonymous functions --- src/librustdoc/html/static/main.js | 506 +++++++++++++++-------------- 1 file changed, 258 insertions(+), 248 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 94d74bf793e7c..28003084f5700 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -450,7 +450,7 @@ function defocusSearchBar() { set_fragment(cur_line_id); } } - })(); + }()); document.addEventListener("click", function(ev) { if (hasClass(ev.target, "collapse-toggle")) { @@ -476,27 +476,29 @@ function defocusSearchBar() { } }); - var x = document.getElementsByClassName("version-selector"); - if (x.length > 0) { - x[0].onchange = function() { - var i, match, - url = document.location.href, - stripped = "", - len = rootPath.match(/\.\.\//g).length + 1; + (function() { + var x = document.getElementsByClassName("version-selector"); + if (x.length > 0) { + x[0].onchange = function() { + var i, match, + url = document.location.href, + stripped = "", + len = rootPath.match(/\.\.\//g).length + 1; - for (i = 0; i < len; ++i) { - match = url.match(/\/[^\/]*$/); - if (i < len - 1) { - stripped = match[0] + stripped; + for (i = 0; i < len; ++i) { + match = url.match(/\/[^\/]*$/); + if (i < len - 1) { + stripped = match[0] + stripped; + } + url = url.substring(0, url.length - match[0].length); } - url = url.substring(0, url.length - match[0].length); - } - url += "/" + document.getElementsByClassName("version-selector")[0].value + stripped; + url += "/" + document.getElementsByClassName("version-selector")[0].value + stripped; - document.location.href = url; - }; - } + document.location.href = url; + }; + } + }()); /** * A function to compute the Levenshtein distance between two strings @@ -2259,7 +2261,7 @@ function defocusSearchBar() { } } - function collapser(e, collapse) { + function collapser(pageId, e, collapse) { // inherent impl ids are like "impl" or impl-'. // they will never be hidden by default. var n = e.parentElement; @@ -2279,7 +2281,7 @@ function defocusSearchBar() { if (impl_list !== null) { onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) { - collapser(e, collapse); + collapser(pageId, e, collapse); }); } @@ -2287,7 +2289,7 @@ function defocusSearchBar() { if (blanket_list !== null) { onEachLazy(blanket_list.getElementsByClassName("collapse-toggle"), function(e) { - collapser(e, collapse); + collapser(pageId, e, collapse); }); } } @@ -2311,103 +2313,7 @@ function defocusSearchBar() { return toggle; } - var toggle = createSimpleToggle(false); - var hideMethodDocs = getCurrentValue("rustdoc-auto-hide-method-docs") === "true"; - var pageId = getPageId(); - - var func = function(e) { - var next = e.nextElementSibling; - if (!next) { - return; - } - if (hasClass(next, "docblock") === true || - (hasClass(next, "stability") === true && - hasClass(next.nextElementSibling, "docblock") === true)) { - var newToggle = toggle.cloneNode(true); - insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]); - if (hideMethodDocs === true && hasClass(e, "method") === true) { - collapseDocs(newToggle, "hide", pageId); - } - } - }; - - var funcImpl = function(e) { - var next = e.nextElementSibling; - if (next && hasClass(next, "docblock")) { - next = next.nextElementSibling; - } - if (!next) { - return; - } - if (next.getElementsByClassName("method").length > 0 && hasClass(e, "impl")) { - insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]); - } - }; - - onEachLazy(document.getElementsByClassName("method"), func); - onEachLazy(document.getElementsByClassName("associatedconstant"), func); - onEachLazy(document.getElementsByClassName("impl"), funcImpl); - var impl_call = function() {}; - if (hideMethodDocs === true) { - impl_call = function(e, newToggle, pageId) { - if (e.id.match(/^impl(?:-\d+)?$/) === null) { - // Automatically minimize all non-inherent impls - if (hasClass(e, "impl") === true) { - collapseDocs(newToggle, "hide", pageId); - } - } - }; - } - var newToggle = document.createElement("a"); - newToggle.href = "javascript:void(0)"; - newToggle.className = "collapse-toggle hidden-default collapsed"; - newToggle.innerHTML = "[" + labelForToggleButton(true) + - "] Show hidden undocumented items"; - function toggleClicked() { - if (hasClass(this, "collapsed")) { - removeClass(this, "collapsed"); - onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) { - if (hasClass(x, "content") === false) { - removeClass(x, "hidden"); - addClass(x, "x"); - } - }, true); - this.innerHTML = "[" + labelForToggleButton(false) + - "] Hide undocumented items"; - } else { - addClass(this, "collapsed"); - onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) { - if (hasClass(x, "content") === false) { - addClass(x, "hidden"); - removeClass(x, "x"); - } - }, true); - this.innerHTML = "[" + labelForToggleButton(true) + - "] Show hidden undocumented items"; - } - } - onEachLazy(document.getElementsByClassName("impl-items"), function(e) { - onEachLazy(e.getElementsByClassName("associatedconstant"), func); - var hiddenElems = e.getElementsByClassName("hidden"); - var needToggle = false; - - var hlength = hiddenElems.length; - for (var i = 0; i < hlength; ++i) { - if (hasClass(hiddenElems[i], "content") === false && - hasClass(hiddenElems[i], "docblock") === false) { - needToggle = true; - break; - } - } - if (needToggle === true) { - var inner_toggle = newToggle.cloneNode(true); - inner_toggle.onclick = toggleClicked; - e.insertBefore(inner_toggle, e.firstChild); - impl_call(e.previousSibling, inner_toggle, pageId); - } - }); - - function createToggle(otherMessage, fontSize, extraClass, show) { + function createToggle(toggle, otherMessage, fontSize, extraClass, show) { var span = document.createElement("span"); span.className = "toggle-label"; if (show) { @@ -2442,97 +2348,197 @@ function defocusSearchBar() { return wrapper; } - var currentType = document.getElementsByClassName("type-decl")[0]; - var className = null; - if (currentType) { - currentType = currentType.getElementsByClassName("rust")[0]; - if (currentType) { - currentType.classList.forEach(function(item) { - if (item !== "main") { - className = item; - return true; + (function() { + var toggle = createSimpleToggle(false); + var hideMethodDocs = getCurrentValue("rustdoc-auto-hide-method-docs") === "true"; + var pageId = getPageId(); + + var func = function(e) { + var next = e.nextElementSibling; + if (!next) { + return; + } + if (hasClass(next, "docblock") === true || + (hasClass(next, "stability") === true && + hasClass(next.nextElementSibling, "docblock") === true)) { + var newToggle = toggle.cloneNode(true); + insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]); + if (hideMethodDocs === true && hasClass(e, "method") === true) { + collapseDocs(newToggle, "hide", pageId); } - }); + } + }; + + var funcImpl = function(e) { + var next = e.nextElementSibling; + if (next && hasClass(next, "docblock")) { + next = next.nextElementSibling; + } + if (!next) { + return; + } + if (next.getElementsByClassName("method").length > 0 && hasClass(e, "impl")) { + insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]); + } + }; + + onEachLazy(document.getElementsByClassName("method"), func); + onEachLazy(document.getElementsByClassName("associatedconstant"), func); + onEachLazy(document.getElementsByClassName("impl"), funcImpl); + var impl_call = function() {}; + if (hideMethodDocs === true) { + impl_call = function(e, newToggle) { + if (e.id.match(/^impl(?:-\d+)?$/) === null) { + // Automatically minimize all non-inherent impls + if (hasClass(e, "impl") === true) { + collapseDocs(newToggle, "hide", pageId); + } + } + }; } - } - var showItemDeclarations = getCurrentValue("rustdoc-auto-hide-" + className); - if (showItemDeclarations === null) { - if (className === "enum" || className === "macro") { - showItemDeclarations = "false"; - } else if (className === "struct" || className === "union" || className === "trait") { - showItemDeclarations = "true"; - } else { - // In case we found an unknown type, we just use the "parent" value. - showItemDeclarations = getCurrentValue("rustdoc-auto-hide-declarations"); + var newToggle = document.createElement("a"); + newToggle.href = "javascript:void(0)"; + newToggle.className = "collapse-toggle hidden-default collapsed"; + newToggle.innerHTML = "[" + labelForToggleButton(true) + + "] Show hidden undocumented items"; + function toggleClicked() { + if (hasClass(this, "collapsed")) { + removeClass(this, "collapsed"); + onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) { + if (hasClass(x, "content") === false) { + removeClass(x, "hidden"); + addClass(x, "x"); + } + }, true); + this.innerHTML = "[" + labelForToggleButton(false) + + "] Hide undocumented items"; + } else { + addClass(this, "collapsed"); + onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) { + if (hasClass(x, "content") === false) { + addClass(x, "hidden"); + removeClass(x, "x"); + } + }, true); + this.innerHTML = "[" + labelForToggleButton(true) + + "] Show hidden undocumented items"; + } } - } - showItemDeclarations = showItemDeclarations === "false"; - function buildToggleWrapper(e) { - if (hasClass(e, "autohide")) { - var wrap = e.previousElementSibling; - if (wrap && hasClass(wrap, "toggle-wrapper")) { - var inner_toggle = wrap.childNodes[0]; - var extra = e.childNodes[0].tagName === "H3"; - - e.style.display = "none"; - addClass(wrap, "collapsed"); - onEachLazy(inner_toggle.getElementsByClassName("inner"), function(e) { - e.innerHTML = labelForToggleButton(true); - }); - onEachLazy(inner_toggle.getElementsByClassName("toggle-label"), function(e) { - e.style.display = "inline-block"; - if (extra === true) { - i_e.innerHTML = " Show " + e.childNodes[0].innerHTML; + onEachLazy(document.getElementsByClassName("impl-items"), function(e) { + onEachLazy(e.getElementsByClassName("associatedconstant"), func); + var hiddenElems = e.getElementsByClassName("hidden"); + var needToggle = false; + + var hlength = hiddenElems.length; + for (var i = 0; i < hlength; ++i) { + if (hasClass(hiddenElems[i], "content") === false && + hasClass(hiddenElems[i], "docblock") === false) { + needToggle = true; + break; + } + } + if (needToggle === true) { + var inner_toggle = newToggle.cloneNode(true); + inner_toggle.onclick = toggleClicked; + e.insertBefore(inner_toggle, e.firstChild); + impl_call(e.previousSibling, inner_toggle); + } + }); + + var currentType = document.getElementsByClassName("type-decl")[0]; + var className = null; + if (currentType) { + currentType = currentType.getElementsByClassName("rust")[0]; + if (currentType) { + currentType.classList.forEach(function(item) { + if (item !== "main") { + className = item; + return true; } }); } } - if (e.parentNode.id === "main") { - var otherMessage = ""; - var fontSize; - var extraClass; - - if (hasClass(e, "type-decl")) { - fontSize = "20px"; - otherMessage = " Show declaration"; - if (showItemDeclarations === false) { - extraClass = "collapsed"; - } - } else if (hasClass(e, "sub-variant")) { - otherMessage = " Show fields"; - } else if (hasClass(e, "non-exhaustive")) { - otherMessage = " This "; - if (hasClass(e, "non-exhaustive-struct")) { - otherMessage += "struct"; - } else if (hasClass(e, "non-exhaustive-enum")) { - otherMessage += "enum"; - } else if (hasClass(e, "non-exhaustive-variant")) { - otherMessage += "enum variant"; - } else if (hasClass(e, "non-exhaustive-type")) { - otherMessage += "type"; - } - otherMessage += " is marked as non-exhaustive"; - } else if (hasClass(e.childNodes[0], "impl-items")) { - extraClass = "marg-left"; - } - - e.parentNode.insertBefore( - createToggle(otherMessage, - fontSize, - extraClass, - hasClass(e, "type-decl") === false || showItemDeclarations === true), - e); - if (hasClass(e, "type-decl") === true && showItemDeclarations === true) { - collapseDocs(e.previousSibling.childNodes[0], "toggle"); - } - if (hasClass(e, "non-exhaustive") === true) { - collapseDocs(e.previousSibling.childNodes[0], "toggle"); + var showItemDeclarations = getCurrentValue("rustdoc-auto-hide-" + className); + if (showItemDeclarations === null) { + if (className === "enum" || className === "macro") { + showItemDeclarations = "false"; + } else if (className === "struct" || className === "union" || className === "trait") { + showItemDeclarations = "true"; + } else { + // In case we found an unknown type, we just use the "parent" value. + showItemDeclarations = getCurrentValue("rustdoc-auto-hide-declarations"); + } + } + showItemDeclarations = showItemDeclarations === "false"; + function buildToggleWrapper(e) { + if (hasClass(e, "autohide")) { + var wrap = e.previousElementSibling; + if (wrap && hasClass(wrap, "toggle-wrapper")) { + var inner_toggle = wrap.childNodes[0]; + var extra = e.childNodes[0].tagName === "H3"; + + e.style.display = "none"; + addClass(wrap, "collapsed"); + onEachLazy(inner_toggle.getElementsByClassName("inner"), function(e) { + e.innerHTML = labelForToggleButton(true); + }); + onEachLazy(inner_toggle.getElementsByClassName("toggle-label"), function(e) { + e.style.display = "inline-block"; + if (extra === true) { + i_e.innerHTML = " Show " + e.childNodes[0].innerHTML; + } + }); + } + } + if (e.parentNode.id === "main") { + var otherMessage = ""; + var fontSize; + var extraClass; + + if (hasClass(e, "type-decl")) { + fontSize = "20px"; + otherMessage = " Show declaration"; + if (showItemDeclarations === false) { + extraClass = "collapsed"; + } + } else if (hasClass(e, "sub-variant")) { + otherMessage = " Show fields"; + } else if (hasClass(e, "non-exhaustive")) { + otherMessage = " This "; + if (hasClass(e, "non-exhaustive-struct")) { + otherMessage += "struct"; + } else if (hasClass(e, "non-exhaustive-enum")) { + otherMessage += "enum"; + } else if (hasClass(e, "non-exhaustive-variant")) { + otherMessage += "enum variant"; + } else if (hasClass(e, "non-exhaustive-type")) { + otherMessage += "type"; + } + otherMessage += " is marked as non-exhaustive"; + } else if (hasClass(e.childNodes[0], "impl-items")) { + extraClass = "marg-left"; + } + + e.parentNode.insertBefore( + createToggle( + toggle, + otherMessage, + fontSize, + extraClass, + hasClass(e, "type-decl") === false || showItemDeclarations === true), + e); + if (hasClass(e, "type-decl") === true && showItemDeclarations === true) { + collapseDocs(e.previousSibling.childNodes[0], "toggle"); + } + if (hasClass(e, "non-exhaustive") === true) { + collapseDocs(e.previousSibling.childNodes[0], "toggle"); + } } } - } - onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper); - onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper); + onEachLazy(document.getElementsByClassName("docblock"), buildToggleWrapper); + onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper); + }()); function createToggleWrapper(tog) { var span = document.createElement("span"); @@ -2547,56 +2553,60 @@ function defocusSearchBar() { return wrapper; } - // To avoid checking on "rustdoc-item-attributes" value on every loop... - var itemAttributesFunc = function() {}; - if (getCurrentValue("rustdoc-auto-hide-attributes") !== "false") { - itemAttributesFunc = function(x) { - collapseDocs(x.previousSibling.childNodes[0], "toggle"); - }; - } - var attributesToggle = createToggleWrapper(createSimpleToggle(false)); - onEachLazy(main.getElementsByClassName("attributes"), function(i_e) { - var attr_tog = attributesToggle.cloneNode(true); - if (hasClass(i_e, "top-attr") === true) { - addClass(attr_tog, "top-attr"); - } - i_e.parentNode.insertBefore(attr_tog, i_e); - itemAttributesFunc(i_e); - }); - - // To avoid checking on "rustdoc-line-numbers" value on every loop... - var lineNumbersFunc = function() {}; - if (getCurrentValue("rustdoc-line-numbers") === "true") { - lineNumbersFunc = function(x) { - var count = x.textContent.split("\n").length; - var elems = []; - for (var i = 0; i < count; ++i) { - elems.push(i + 1); - } - var node = document.createElement("pre"); - addClass(node, "line-number"); - node.innerHTML = elems.join("\n"); - x.parentNode.insertBefore(node, x); - }; - } - onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) { - if (hasClass(e, "compile_fail")) { - e.addEventListener("mouseover", function(event) { - this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00"; - }); - e.addEventListener("mouseout", function(event) { - this.parentElement.previousElementSibling.childNodes[0].style.color = ""; - }); - } else if (hasClass(e, "ignore")) { - e.addEventListener("mouseover", function(event) { - this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200"; - }); - e.addEventListener("mouseout", function(event) { - this.parentElement.previousElementSibling.childNodes[0].style.color = ""; - }); + (function() { + // To avoid checking on "rustdoc-item-attributes" value on every loop... + var itemAttributesFunc = function() {}; + if (getCurrentValue("rustdoc-auto-hide-attributes") !== "false") { + itemAttributesFunc = function(x) { + collapseDocs(x.previousSibling.childNodes[0], "toggle"); + }; } - lineNumbersFunc(e); - }); + var attributesToggle = createToggleWrapper(createSimpleToggle(false)); + onEachLazy(main.getElementsByClassName("attributes"), function(i_e) { + var attr_tog = attributesToggle.cloneNode(true); + if (hasClass(i_e, "top-attr") === true) { + addClass(attr_tog, "top-attr"); + } + i_e.parentNode.insertBefore(attr_tog, i_e); + itemAttributesFunc(i_e); + }); + }()); + + (function() { + // To avoid checking on "rustdoc-line-numbers" value on every loop... + var lineNumbersFunc = function() {}; + if (getCurrentValue("rustdoc-line-numbers") === "true") { + lineNumbersFunc = function(x) { + var count = x.textContent.split("\n").length; + var elems = []; + for (var i = 0; i < count; ++i) { + elems.push(i + 1); + } + var node = document.createElement("pre"); + addClass(node, "line-number"); + node.innerHTML = elems.join("\n"); + x.parentNode.insertBefore(node, x); + }; + } + onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) { + if (hasClass(e, "compile_fail")) { + e.addEventListener("mouseover", function(event) { + this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00"; + }); + e.addEventListener("mouseout", function(event) { + this.parentElement.previousElementSibling.childNodes[0].style.color = ""; + }); + } else if (hasClass(e, "ignore")) { + e.addEventListener("mouseover", function(event) { + this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200"; + }); + e.addEventListener("mouseout", function(event) { + this.parentElement.previousElementSibling.childNodes[0].style.color = ""; + }); + } + lineNumbersFunc(e); + }); + }()); // In the search display, allows to switch between tabs. function printTab(nb) { From 872ddf243e4a019d7d2ad5c803b21bffc34ea9cb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 17 May 2020 14:57:19 +0200 Subject: [PATCH 304/695] Reexported functions are now declared directly as "windows" field --- src/librustdoc/html/static/main.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 28003084f5700..ba308c97f30e8 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -535,7 +535,7 @@ function defocusSearchBar() { return s1_len + s2_len; } - function initSearch(rawSearchIndex) { + window.initSearch = function(rawSearchIndex) { var MAX_LEV_DISTANCE = 3; var MAX_RESULTS = 200; var GENERICS_DATA = 1; @@ -1930,12 +1930,11 @@ function defocusSearchBar() { sidebar.appendChild(div); } } - } + }; - window.initSearch = initSearch; // delayed sidebar rendering. - function initSidebarItems(items) { + window.initSidebarItems = function(items) { var sidebar = document.getElementsByClassName("sidebar-elems")[0]; var current = window.sidebarCurrent; @@ -1997,9 +1996,7 @@ function defocusSearchBar() { block("foreigntype", "Foreign Types"); block("keyword", "Keywords"); block("traitalias", "Trait Aliases"); - } - - window.initSidebarItems = initSidebarItems; + }; window.register_implementors = function(imp) { var implementors = document.getElementById("implementors-list"); @@ -2699,7 +2696,7 @@ function defocusSearchBar() { }); } - function addSearchOptions(crates) { + window.addSearchOptions = function(crates) { var elem = document.getElementById("crate-search"); if (!elem) { @@ -2744,9 +2741,7 @@ function defocusSearchBar() { if (search_input) { search_input.removeAttribute('disabled'); }; - } - - window.addSearchOptions = addSearchOptions; + }; function buildHelperPopup() { var popup = document.createElement("aside"); From f41d284ea0b87187e84d6edab4f9a71542cfd1b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 17 May 2020 15:34:59 +0200 Subject: [PATCH 305/695] Fix eslint lints --- src/librustdoc/html/static/main.js | 54 +++++++++------------ src/librustdoc/html/static/settings.js | 3 ++ src/librustdoc/html/static/source-script.js | 2 +- src/librustdoc/html/static/storage.js | 9 +++- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ba308c97f30e8..8413f9397067f 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -3,7 +3,7 @@ // Local js definitions: /* global addClass, getCurrentValue, hasClass */ -/* global onEach, removeClass, updateLocalStorage */ +/* global onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */ if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { @@ -192,6 +192,7 @@ function defocusSearchBar() { var savedHash = ""; function handleHashes(ev) { + var elem; var search = getSearchElement(); if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) { // This block occurs when clicking on an element in the navbar while @@ -201,7 +202,7 @@ function defocusSearchBar() { if (browserSupportsHistoryApi()) { history.replaceState(hash, "", "?search=#" + hash); } - var elem = document.getElementById(hash); + elem = document.getElementById(hash); if (elem) { elem.scrollIntoView(); } @@ -212,7 +213,7 @@ function defocusSearchBar() { if (savedHash.length === 0) { return; } - var elem = document.getElementById(savedHash.slice(1)); // we remove the '#' + elem = document.getElementById(savedHash.slice(1)); // we remove the '#' if (!elem || !isHidden(elem)) { return; } @@ -335,7 +336,7 @@ function defocusSearchBar() { } function displayHelp(display, ev, help) { - var help = help ? help : getHelpElement(); + help = help ? help : getHelpElement(); if (display === true) { if (hasClass(help, "hidden")) { ev.preventDefault(); @@ -449,7 +450,7 @@ function defocusSearchBar() { set_fragment(cur_line_id); } - } + }; }()); document.addEventListener("click", function(ev) { @@ -615,7 +616,7 @@ function defocusSearchBar() { function sortResults(results, isType) { var ar = []; for (var entry in results) { - if (results.hasOwnProperty(entry)) { + if (hasOwnProperty(results, entry)) { ar.push(results[entry]); } } @@ -1113,8 +1114,6 @@ function defocusSearchBar() { } fullId = generateId(ty); - // allow searching for void (no output) functions as well - var typeOutput = type.length > OUTPUT_DATA ? type[OUTPUT_DATA].name : ""; returned = checkReturned(ty, output, true, NO_TYPE_FILTER); if (output.name === "*" || returned === true) { in_args = false; @@ -1177,7 +1176,6 @@ function defocusSearchBar() { var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1); var lev; - var lev_distance; for (j = 0; j < nSearchWords; ++j) { ty = searchIndex[j]; if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) { @@ -1674,7 +1672,7 @@ function defocusSearchBar() { function getFilterCrates() { var elem = document.getElementById("crate-search"); - if (elem && elem.value !== "All crates" && rawSearchIndex.hasOwnProperty(elem.value)) { + if (elem && elem.value !== "All crates" && hasOwnProperty(rawSearchIndex, elem.value)) { return elem.value; } return undefined; @@ -1722,7 +1720,7 @@ function defocusSearchBar() { var currentIndex = 0; for (var crate in rawSearchIndex) { - if (!rawSearchIndex.hasOwnProperty(crate)) { continue; } + if (!hasOwnProperty(rawSearchIndex, crate)) { continue; } var crateSize = 0; @@ -1906,7 +1904,7 @@ function defocusSearchBar() { var crates = []; for (var crate in rawSearchIndex) { - if (!rawSearchIndex.hasOwnProperty(crate)) { + if (!hasOwnProperty(rawSearchIndex, crate)) { continue; } crates.push(crate); @@ -2173,19 +2171,13 @@ function defocusSearchBar() { } } var ns = n.nextElementSibling; - while (true) { - if (ns && ( - hasClass(ns, "docblock") || - hasClass(ns, "stability"))) { - if (addOrRemove) { - addClass(ns, "hidden-by-impl-hider"); - } else { - removeClass(ns, "hidden-by-impl-hider"); - } - ns = ns.nextElementSibling; - continue; + while (ns && (hasClass(ns, "docblock") || hasClass(ns, "stability"))) { + if (addOrRemove) { + addClass(ns, "hidden-by-impl-hider"); + } else { + removeClass(ns, "hidden-by-impl-hider"); } - break; + ns = ns.nextElementSibling; } } }; @@ -2482,7 +2474,7 @@ function defocusSearchBar() { onEachLazy(inner_toggle.getElementsByClassName("toggle-label"), function(e) { e.style.display = "inline-block"; if (extra === true) { - i_e.innerHTML = " Show " + e.childNodes[0].innerHTML; + e.innerHTML = " Show " + e.childNodes[0].innerHTML; } }); } @@ -2587,17 +2579,17 @@ function defocusSearchBar() { } onEachLazy(document.getElementsByClassName("rust-example-rendered"), function(e) { if (hasClass(e, "compile_fail")) { - e.addEventListener("mouseover", function(event) { + e.addEventListener("mouseover", function() { this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00"; }); - e.addEventListener("mouseout", function(event) { + e.addEventListener("mouseout", function() { this.parentElement.previousElementSibling.childNodes[0].style.color = ""; }); } else if (hasClass(e, "ignore")) { - e.addEventListener("mouseover", function(event) { + e.addEventListener("mouseover", function() { this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200"; }); - e.addEventListener("mouseout", function(event) { + e.addEventListener("mouseout", function() { this.parentElement.previousElementSibling.childNodes[0].style.color = ""; }); } @@ -2705,7 +2697,7 @@ function defocusSearchBar() { var crates_text = []; if (Object.keys(crates).length > 1) { for (var crate in crates) { - if (crates.hasOwnProperty(crate)) { + if (hasOwnProperty(crates, crate)) { crates_text.push(crate); } } @@ -2740,7 +2732,7 @@ function defocusSearchBar() { if (search_input) { search_input.removeAttribute('disabled'); - }; + } }; function buildHelperPopup() { diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js index c21db7371f3c3..427a74c0c87fa 100644 --- a/src/librustdoc/html/static/settings.js +++ b/src/librustdoc/html/static/settings.js @@ -1,3 +1,6 @@ +// Local js definitions: +/* global getCurrentValue, updateLocalStorage */ + (function () { function changeSetting(settingName, isEnabled) { updateLocalStorage('rustdoc-' + settingName, isEnabled); diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index 567022b4139ad..cfbfe6675f52b 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -1,5 +1,5 @@ // From rust: -/* global sourcesIndex */ +/* global search, sourcesIndex */ // Local js definitions: /* global addClass, getCurrentValue, hasClass, removeClass, updateLocalStorage */ diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index d142d99ac704d..0a2fae274fa87 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -27,14 +27,15 @@ function removeClass(elem, className) { function onEach(arr, func, reversed) { if (arr && arr.length > 0 && func) { var length = arr.length; + var i; if (reversed !== true) { - for (var i = 0; i < length; ++i) { + for (i = 0; i < length; ++i) { if (func(arr[i]) === true) { return true; } } } else { - for (var i = length - 1; i >= 0; --i) { + for (i = length - 1; i >= 0; --i) { if (func(arr[i]) === true) { return true; } @@ -51,6 +52,10 @@ function onEachLazy(lazyArray, func, reversed) { reversed); } +function hasOwnProperty(obj, property) { + return Object.prototype.hasOwnProperty.call(obj, property); +} + function usableLocalStorage() { // Check if the browser supports localStorage at all: if (typeof Storage === "undefined") { From 6faa82be42df548877315768184f8cfba111772e Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 26 May 2020 11:04:34 +0100 Subject: [PATCH 306/695] Eagerly lower asm sub-expressions to HIR even if there is an error Fixes #72570 --- src/librustc_ast_lowering/expr.rs | 68 ++++++++++++++++--------------- src/test/ui/asm/issue-72570.rs | 7 ++++ 2 files changed, 42 insertions(+), 33 deletions(-) create mode 100644 src/test/ui/asm/issue-72570.rs diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 5bcd111706f35..d8002bd3e19ae 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -974,20 +974,18 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> { - let asm_arch = if let Some(asm_arch) = self.sess.asm_arch { - asm_arch - } else { + if self.sess.asm_arch.is_none() { struct_span_err!(self.sess, sp, E0472, "asm! is unsupported on this target").emit(); - return hir::ExprKind::Err; }; - if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { - match asm_arch { - asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64 => {} - _ => self - .sess - .struct_span_err(sp, "the `att_syntax` option is only supported on x86") - .emit(), - } + if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) + && !matches!( + self.sess.asm_arch, + Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64) + ) + { + self.sess + .struct_span_err(sp, "the `att_syntax` option is only supported on x86") + .emit(); } // Lower operands to HIR, filter_map skips any operands with invalid @@ -1001,10 +999,8 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(match reg { InlineAsmRegOrRegClass::Reg(s) => asm::InlineAsmRegOrRegClass::Reg( asm::InlineAsmReg::parse( - asm_arch, - |feature| { - self.sess.target_features.contains(&Symbol::intern(feature)) - }, + sess.asm_arch?, + |feature| sess.target_features.contains(&Symbol::intern(feature)), s, ) .map_err(|e| { @@ -1015,7 +1011,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ), InlineAsmRegOrRegClass::RegClass(s) => { asm::InlineAsmRegOrRegClass::RegClass( - asm::InlineAsmRegClass::parse(asm_arch, s) + asm::InlineAsmRegClass::parse(sess.asm_arch?, s) .map_err(|e| { let msg = format!( "invalid register class `{}`: {}", @@ -1029,33 +1025,38 @@ impl<'hir> LoweringContext<'_, 'hir> { } }) }; - let op = match op { - InlineAsmOperand::In { reg, expr } => hir::InlineAsmOperand::In { - reg: lower_reg(*reg)?, + + // lower_reg is executed last because we need to lower all + // sub-expressions even if we throw them away later. + let op = match *op { + InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In { expr: self.lower_expr_mut(expr), + reg: lower_reg(reg)?, }, - InlineAsmOperand::Out { reg, late, expr } => hir::InlineAsmOperand::Out { - reg: lower_reg(*reg)?, - late: *late, + InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out { + late, expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)), + reg: lower_reg(reg)?, }, - InlineAsmOperand::InOut { reg, late, expr } => hir::InlineAsmOperand::InOut { - reg: lower_reg(*reg)?, - late: *late, - expr: self.lower_expr_mut(expr), - }, - InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { + InlineAsmOperand::InOut { reg, late, ref expr } => { + hir::InlineAsmOperand::InOut { + late, + expr: self.lower_expr_mut(expr), + reg: lower_reg(reg)?, + } + } + InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => { hir::InlineAsmOperand::SplitInOut { - reg: lower_reg(*reg)?, - late: *late, + late, in_expr: self.lower_expr_mut(in_expr), out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)), + reg: lower_reg(reg)?, } } - InlineAsmOperand::Const { expr } => { + InlineAsmOperand::Const { ref expr } => { hir::InlineAsmOperand::Const { expr: self.lower_expr_mut(expr) } } - InlineAsmOperand::Sym { expr } => { + InlineAsmOperand::Sym { ref expr } => { hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) } } }; @@ -1069,6 +1070,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } // Validate template modifiers against the register classes for the operands + let asm_arch = sess.asm_arch.unwrap(); for p in &asm.template { if let InlineAsmTemplatePiece::Placeholder { operand_idx, diff --git a/src/test/ui/asm/issue-72570.rs b/src/test/ui/asm/issue-72570.rs new file mode 100644 index 0000000000000..df508e9045819 --- /dev/null +++ b/src/test/ui/asm/issue-72570.rs @@ -0,0 +1,7 @@ +#![feature(asm)] + +fn main() { + unsafe { + asm!("", in("invalid") "".len()); + } +} From 7aa8946c7271f7077df537ed8e3e0b544252c466 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 26 May 2020 11:13:04 +0100 Subject: [PATCH 307/695] Update src/librustc_ast_lowering/expr.rs Co-authored-by: Oliver Scherer --- src/librustc_ast_lowering/expr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index d8002bd3e19ae..b7f2e9a9050df 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -976,7 +976,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> { if self.sess.asm_arch.is_none() { struct_span_err!(self.sess, sp, E0472, "asm! is unsupported on this target").emit(); - }; + } if asm.options.contains(InlineAsmOptions::ATT_SYNTAX) && !matches!( self.sess.asm_arch, From de53276aac3f9cb89fff5d9db3741e8c7852920a Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 26 May 2020 11:27:27 +0100 Subject: [PATCH 308/695] Fix test --- src/test/ui/asm/issue-72570.rs | 3 +++ src/test/ui/asm/issue-72570.stderr | 8 ++++++++ 2 files changed, 11 insertions(+) create mode 100644 src/test/ui/asm/issue-72570.stderr diff --git a/src/test/ui/asm/issue-72570.rs b/src/test/ui/asm/issue-72570.rs index df508e9045819..f34525a664ebe 100644 --- a/src/test/ui/asm/issue-72570.rs +++ b/src/test/ui/asm/issue-72570.rs @@ -1,7 +1,10 @@ +// only-x86_64 + #![feature(asm)] fn main() { unsafe { asm!("", in("invalid") "".len()); + //~^ ERROR: invalid register `invalid`: unknown register } } diff --git a/src/test/ui/asm/issue-72570.stderr b/src/test/ui/asm/issue-72570.stderr new file mode 100644 index 0000000000000..49013a23ced2d --- /dev/null +++ b/src/test/ui/asm/issue-72570.stderr @@ -0,0 +1,8 @@ +error: invalid register `invalid`: unknown register + --> $DIR/issue-72570.rs:7:18 + | +LL | asm!("", in("invalid") "".len()); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 05a221216a7f975c9aece42b5cde05a129092a1f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 May 2020 14:11:35 +0200 Subject: [PATCH 309/695] Remove font-display settings --- src/librustdoc/html/static/rustdoc.css | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index b1e0ab9ca64fd..2cb3347135c1b 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -3,14 +3,12 @@ font-family: 'Fira Sans'; font-style: normal; font-weight: 400; - font-display: optional; src: local('Fira Sans'), url("FiraSans-Regular.woff") format('woff'); } @font-face { font-family: 'Fira Sans'; font-style: normal; font-weight: 500; - font-display: optional; src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff'); } @@ -19,23 +17,18 @@ font-family: 'Source Serif Pro'; font-style: normal; font-weight: 400; - /* The difference for body text without this font is greater than other fonts, - * so the 0~100ms block of fallback is preferred over optional, for legibility. */ - font-display: fallback; src: local('Source Serif Pro'), url("SourceSerifPro-Regular.ttf.woff") format('woff'); } @font-face { font-family: 'Source Serif Pro'; font-style: italic; font-weight: 400; - font-display: optional; src: local('Source Serif Pro Italic'), url("SourceSerifPro-It.ttf.woff") format('woff'); } @font-face { font-family: 'Source Serif Pro'; font-style: normal; font-weight: 700; - font-display: optional; src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.ttf.woff") format('woff'); } @@ -44,7 +37,6 @@ font-family: 'Source Code Pro'; font-style: normal; font-weight: 400; - font-display: optional; /* Avoid using locally installed font because bad versions are in circulation: * see https://github.com/rust-lang/rust/issues/24355 */ src: url("SourceCodePro-Regular.woff") format('woff'); @@ -53,7 +45,6 @@ font-family: 'Source Code Pro'; font-style: normal; font-weight: 600; - font-display: optional; src: url("SourceCodePro-Semibold.woff") format('woff'); } From a423d2d4b0812339e10fd5101fddb31780061903 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 May 2020 11:48:59 +0200 Subject: [PATCH 310/695] Improve formatting --- src/librustdoc/html/static/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 8413f9397067f..22c9426db2036 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -57,7 +57,6 @@ function defocusSearchBar() { getSearchInput().blur(); } - (function() { "use strict"; @@ -494,7 +493,8 @@ function defocusSearchBar() { url = url.substring(0, url.length - match[0].length); } - url += "/" + document.getElementsByClassName("version-selector")[0].value + stripped; + var selectedVersion = document.getElementsByClassName("version-selector")[0].value; + url += "/" + selectedVersion + stripped; document.location.href = url; }; From 398511a1352ab5b6d5fd8f2c9e80b357f6b84441 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 May 2020 15:11:36 +0200 Subject: [PATCH 311/695] Import missing functions from storage.js --- src/tools/rustdoc-js/tester.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 1fa46ce99f5e6..163571bc5b988 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -241,7 +241,7 @@ function loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate) { ALIASES = {}; finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; finalJS += 'var rootPath = "../";\n'; - finalJS += loadThings(["onEach"], 'function', extractFunction, storageJs); + finalJS += loadThings(["hasOwnProperty", "onEach"], 'function', extractFunction, storageJs); finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); From 2b26b8b32bb2246caa0a82b6ea16f11da3686d0e Mon Sep 17 00:00:00 2001 From: Jonathan Schwender Date: Tue, 26 May 2020 15:16:57 +0200 Subject: [PATCH 312/695] Fix documentation example for gcov profiling Incremental compilation needs to be turned off. Also added the other RUSTFLAGS that should/need to be turned on. --- src/doc/unstable-book/src/compiler-flags/profile.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/doc/unstable-book/src/compiler-flags/profile.md b/src/doc/unstable-book/src/compiler-flags/profile.md index 452aca51532c9..b3b3e4eb4058f 100644 --- a/src/doc/unstable-book/src/compiler-flags/profile.md +++ b/src/doc/unstable-book/src/compiler-flags/profile.md @@ -12,10 +12,15 @@ For example: ```Bash cargo new testgcov --bin cd testgcov -export RUSTFLAGS="-Zprofile" +export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort" +export CARGO_INCREMENTAL=0 cargo build cargo run ``` Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created. You can parse them with [llvm-cov gcov](https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/mozilla/grcov). + +Please note that `RUSTFLAGS` apply to everything that cargo builds and runs during a build, including build scripts! +To avoid this, pass a `RUSTC_WRAPPER` program to cargo that only adds the profiling flags to rustc for the specific +crates you want to profile. From afd88f2a332df214d0c3a2cfbe9cc05482955a98 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 5 May 2020 14:25:58 -0700 Subject: [PATCH 313/695] Export ZERO_AR_DATE for macos linker invocations This commit attempts to improve reproducibility of builds on macOS by exporting the `ZERO_AR_DATE=1` environment variable for all invocations of the linker. While it looks like this env var is targeted at just the `ar` command (which does actually read this) it appears that recent-ish versions of the linker *also* read this environment variable. This env var forces the linker to set a deterministic zero value for the mtime in the N_OSO field of the object file. Currently it's believe that older versions of the linker will simply ignore this env var, while newer versions will read it and produce a deterministic output for compilations with debuginfo. Closes #47086 Closes #66568 --- src/librustc_target/spec/apple_base.rs | 11 +++++++++++ .../run-make-fulldeps/reproducible-build-2/Makefile | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/librustc_target/spec/apple_base.rs b/src/librustc_target/spec/apple_base.rs index 4ad65569e6a8a..bdd5a893d34e2 100644 --- a/src/librustc_target/spec/apple_base.rs +++ b/src/librustc_target/spec/apple_base.rs @@ -31,6 +31,17 @@ pub fn opts() -> TargetOptions { has_elf_tls: version >= (10, 7), abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, + + // This environment variable is pretty magical but is intended for + // producing deterministic builds. This was first discovered to be used + // by the `ar` tool as a way to control whether or not mtime entries in + // the archive headers were set to zero or not. It appears that + // eventually the linker got updated to do the same thing and now reads + // this environment variable too in recent versions. + // + // For some more info see the commentary on #47086 + link_env: vec![("ZERO_AR_DATE".to_string(), "1".to_string())], + ..Default::default() } } diff --git a/src/test/run-make-fulldeps/reproducible-build-2/Makefile b/src/test/run-make-fulldeps/reproducible-build-2/Makefile index fc912efed5e3c..fd94516fbbaf6 100644 --- a/src/test/run-make-fulldeps/reproducible-build-2/Makefile +++ b/src/test/run-make-fulldeps/reproducible-build-2/Makefile @@ -2,7 +2,6 @@ # ignore-musl # ignore-windows -# ignore-macos (rust-lang/rust#66568) # Objects are reproducible but their path is not. all: \ @@ -21,7 +20,7 @@ sysroot: rm -rf $(TMPDIR) && mkdir $(TMPDIR) $(RUSTC) reproducible-build-aux.rs $(RUSTC) reproducible-build.rs --crate-type rlib --sysroot $(shell $(RUSTC) --print sysroot) --remap-path-prefix=$(shell $(RUSTC) --print sysroot)=/sysroot - cp -r $(shell $(RUSTC) --print sysroot) $(TMPDIR)/sysroot + cp -R $(shell $(RUSTC) --print sysroot) $(TMPDIR)/sysroot cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfoo.rlib $(RUSTC) reproducible-build.rs --crate-type rlib --sysroot $(TMPDIR)/sysroot --remap-path-prefix=$(TMPDIR)/sysroot=/sysroot cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1 From 67167be1679c60eefa2c314c5e4a2b673d5eef11 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Sun, 17 May 2020 18:14:43 +0200 Subject: [PATCH 314/695] Make empty_line_after_outer_attr an early lint --- clippy_lints/Cargo.toml | 4 + clippy_lints/src/attrs.rs | 75 +++++++++++-------- tests/compile-test.rs | 2 +- tests/ui/auxiliary/proc_macro_attr.rs | 37 +++++++++ tests/ui/empty_line_after_outer_attribute.rs | 19 ++++- .../empty_line_after_outer_attribute.stderr | 12 +-- 6 files changed, 109 insertions(+), 40 deletions(-) create mode 100644 tests/ui/auxiliary/proc_macro_attr.rs diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 1c0be72783462..043a79f200199 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -33,5 +33,9 @@ semver = "0.9.0" # see url = { version = "2.1.0", features = ["serde"] } +[dev-dependencies] +quote = "*" +syn = { version = "*", features = ["full"] } + [features] deny-warnings = [] diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 64abc9fdc7174..41f125d48398f 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -248,7 +248,6 @@ declare_lint_pass!(Attributes => [ INLINE_ALWAYS, DEPRECATED_SEMVER, USELESS_ATTRIBUTE, - EMPTY_LINE_AFTER_OUTER_ATTR, UNKNOWN_CLIPPY_LINTS, ]); @@ -480,36 +479,6 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib } for attr in attrs { - let attr_item = if let AttrKind::Normal(ref attr) = attr.kind { - attr - } else { - continue; - }; - - if attr.style == AttrStyle::Outer { - if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) { - return; - } - - let begin_of_attr_to_item = Span::new(attr.span.lo(), span.lo(), span.ctxt()); - let end_of_attr_to_item = Span::new(attr.span.hi(), span.lo(), span.ctxt()); - - if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) { - let lines = snippet.split('\n').collect::>(); - let lines = without_block_comments(lines); - - if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - span_lint( - cx, - EMPTY_LINE_AFTER_OUTER_ATTR, - begin_of_attr_to_item, - "Found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - ); - } - } - } - if let Some(values) = attr.meta_item_list() { if values.len() != 1 || !attr.check_name(sym!(inline)) { continue; @@ -551,15 +520,57 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { } } -declare_lint_pass!(EarlyAttributes => [DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS]); +declare_lint_pass!(EarlyAttributes => [ + DEPRECATED_CFG_ATTR, + MISMATCHED_TARGET_OS, + EMPTY_LINE_AFTER_OUTER_ATTR, +]); impl EarlyLintPass for EarlyAttributes { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::ast::Item) { + check_empty_line_after_outer_attr(cx, item); + } + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { check_deprecated_cfg_attr(cx, attr); check_mismatched_target_os(cx, attr); } } +fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::ast::Item) { + for attr in &item.attrs { + let attr_item = if let AttrKind::Normal(ref attr) = attr.kind { + attr + } else { + return; + }; + + if attr.style == AttrStyle::Outer { + if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) { + return; + } + + let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt()); + let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt()); + + if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) { + let lines = snippet.split('\n').collect::>(); + let lines = without_block_comments(lines); + + if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { + span_lint( + cx, + EMPTY_LINE_AFTER_OUTER_ATTR, + begin_of_attr_to_item, + "Found an empty line after an outer attribute. \ + Perhaps you forgot to add a `!` to make it an inner attribute?", + ); + } + } + } + } +} + fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { if_chain! { // check cfg_attr diff --git a/tests/compile-test.rs b/tests/compile-test.rs index a5de84293909f..2758b9a7e7604 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -38,7 +38,7 @@ fn clippy_driver_path() -> PathBuf { // as what we manually pass to `cargo` invocation fn third_party_crates() -> String { use std::collections::HashMap; - static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints"]; + static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints", "syn", "quote"]; let dep_dir = cargo::TARGET_LIB.join("deps"); let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len()); for entry in fs::read_dir(dep_dir).unwrap() { diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs new file mode 100644 index 0000000000000..e6626d57a7722 --- /dev/null +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -0,0 +1,37 @@ +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(repr128, proc_macro_hygiene, proc_macro_quote)] +#![allow(clippy::useless_conversion)] + +extern crate proc_macro; +extern crate quote; +extern crate syn; + +use proc_macro::TokenStream; +use quote::{quote, quote_spanned}; +use syn::parse_macro_input; +use syn::{parse_quote, ItemTrait, TraitItem}; + +#[proc_macro_attribute] +pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream { + let mut item = parse_macro_input!(input as ItemTrait); + for inner in &mut item.items { + if let TraitItem::Method(method) = inner { + let sig = &method.sig; + let block = &mut method.default; + if let Some(block) = block { + let brace = block.brace_token; + + let my_block = quote_spanned!( brace.span => { + // Should not trigger `empty_line_after_outer_attr` + #[crate_type = "lib"] + #sig #block + Vec::new() + }); + *block = parse_quote!(#my_block); + } + } + } + TokenStream::from(quote!(#item)) +} diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 5343dff9da1db..3e92bca986ab5 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -1,8 +1,12 @@ +// aux-build:proc_macro_attr.rs #![warn(clippy::empty_line_after_outer_attr)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] #![rustfmt::skip] +#[macro_use] +extern crate proc_macro_attr; + // This should produce a warning #[crate_type = "lib"] @@ -93,4 +97,17 @@ pub struct S; /* test */ pub struct T; -fn main() { } +// This should not produce a warning +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +fn main() {} diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr index d8c9786541f0b..bf753a732f000 100644 --- a/tests/ui/empty_line_after_outer_attribute.stderr +++ b/tests/ui/empty_line_after_outer_attribute.stderr @@ -1,5 +1,5 @@ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:7:1 + --> $DIR/empty_line_after_outer_attribute.rs:11:1 | LL | / #[crate_type = "lib"] LL | | @@ -10,7 +10,7 @@ LL | | fn with_one_newline_and_comment() { assert!(true) } = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:19:1 + --> $DIR/empty_line_after_outer_attribute.rs:23:1 | LL | / #[crate_type = "lib"] LL | | @@ -18,7 +18,7 @@ LL | | fn with_one_newline() { assert!(true) } | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:24:1 + --> $DIR/empty_line_after_outer_attribute.rs:28:1 | LL | / #[crate_type = "lib"] LL | | @@ -27,7 +27,7 @@ LL | | fn with_two_newlines() { assert!(true) } | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:31:1 + --> $DIR/empty_line_after_outer_attribute.rs:35:1 | LL | / #[crate_type = "lib"] LL | | @@ -35,7 +35,7 @@ LL | | enum Baz { | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:39:1 + --> $DIR/empty_line_after_outer_attribute.rs:43:1 | LL | / #[crate_type = "lib"] LL | | @@ -43,7 +43,7 @@ LL | | struct Foo { | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:47:1 + --> $DIR/empty_line_after_outer_attribute.rs:51:1 | LL | / #[crate_type = "lib"] LL | | From e3f6a8fc20ce778168e079257b7a33a47fe8541f Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Sun, 17 May 2020 19:09:07 +0200 Subject: [PATCH 315/695] Specify quote and syn versions --- clippy_lints/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 043a79f200199..11586083d8c78 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -34,8 +34,8 @@ semver = "0.9.0" url = { version = "2.1.0", features = ["serde"] } [dev-dependencies] -quote = "*" -syn = { version = "*", features = ["full"] } +quote = "1.0.2" +syn = { version = "1.0.11", features = ["full"] } [features] deny-warnings = [] From cdff59e156a85d86f7abb9834e42a18fe1ee257e Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Sun, 17 May 2020 19:13:33 +0200 Subject: [PATCH 316/695] Using dev-dependencies doesn't seem to work w/ compiletest --- clippy_lints/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 11586083d8c78..7514608bc7e8a 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -32,8 +32,6 @@ semver = "0.9.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } - -[dev-dependencies] quote = "1.0.2" syn = { version = "1.0.11", features = ["full"] } From fd86b3150e21df8eb6fee2f0c8b69f323146ffad Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Tue, 26 May 2020 16:51:04 +0200 Subject: [PATCH 317/695] Be less specific about quote and syn versions --- clippy_lints/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 7514608bc7e8a..76baf27fb2dbf 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -32,8 +32,8 @@ semver = "0.9.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } -quote = "1.0.2" -syn = { version = "1.0.11", features = ["full"] } +quote = "1" +syn = { version = "1", features = ["full"] } [features] deny-warnings = [] From ca722b935835f7ce3acfbb840141cc17941fc63b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 22:29:06 +0900 Subject: [PATCH 318/695] Add test for #56445 --- src/test/ui/impl-trait/issue-56445.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-56445.rs diff --git a/src/test/ui/impl-trait/issue-56445.rs b/src/test/ui/impl-trait/issue-56445.rs new file mode 100644 index 0000000000000..a34d7bae3a6ca --- /dev/null +++ b/src/test/ui/impl-trait/issue-56445.rs @@ -0,0 +1,26 @@ +// Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-629426939 +// check-pass + +#![crate_type = "lib"] + +use std::marker::PhantomData; + +pub struct S<'a> +{ + pub m1: PhantomData<&'a u8>, + pub m2: [u8; S::size()], +} + +impl<'a> S<'a> +{ + pub const fn size() -> usize { 1 } + + pub fn new() -> Self + { + Self + { + m1: PhantomData, + m2: [0; Self::size()], + } + } +} From 125f0abb42159d3db9d86208e03006d068585bbf Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 22:29:25 +0900 Subject: [PATCH 319/695] Add test for #68532 --- src/test/ui/impl-trait/issue-68532.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/test/ui/impl-trait/issue-68532.rs diff --git a/src/test/ui/impl-trait/issue-68532.rs b/src/test/ui/impl-trait/issue-68532.rs new file mode 100644 index 0000000000000..01a7af0aee40e --- /dev/null +++ b/src/test/ui/impl-trait/issue-68532.rs @@ -0,0 +1,13 @@ +// check-pass + +pub struct A<'a>(&'a ()); + +impl<'a> A<'a> { + const N: usize = 68; + + pub fn foo(&self) { + let _b = [0; Self::N]; + } +} + +fn main() {} From 4b87f97ca8862ad97272ecafcd4c27334ecb81aa Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 25 May 2020 22:29:34 +0900 Subject: [PATCH 320/695] Add test for #70121 --- .../ui/type-alias-impl-trait/issue-70121.rs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/ui/type-alias-impl-trait/issue-70121.rs diff --git a/src/test/ui/type-alias-impl-trait/issue-70121.rs b/src/test/ui/type-alias-impl-trait/issue-70121.rs new file mode 100644 index 0000000000000..dff0d89d465dd --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-70121.rs @@ -0,0 +1,23 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +pub type Successors<'a> = impl Iterator; + +pub fn f<'a>() -> Successors<'a> { + None.into_iter() +} + +pub trait Tr { + type Item; +} + +impl<'a> Tr for &'a () { + type Item = Successors<'a>; +} + +pub fn kazusa<'a>() -> <&'a () as Tr>::Item { + None.into_iter() +} + +fn main() {} From 6315d0c99eead181e3725623c6a9d01950620640 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 27 May 2020 00:48:29 +0900 Subject: [PATCH 321/695] Add test for #71042 --- ...ssue-71042-opaquely-typed-constant-used-in-pattern.rs | 9 +++++++++ ...-71042-opaquely-typed-constant-used-in-pattern.stderr | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs create mode 100644 src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs new file mode 100644 index 0000000000000..c5e4a72fb9ff1 --- /dev/null +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs @@ -0,0 +1,9 @@ +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +fn main() { + const C: impl Copy = 0; + match C { + C | _ => {} //~ ERROR: opaque types cannot be used in patterns + } +} diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr new file mode 100644 index 0000000000000..7695223f2cf98 --- /dev/null +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr @@ -0,0 +1,8 @@ +error: opaque types cannot be used in patterns + --> $DIR/issue-71042-opaquely-typed-constant-used-in-pattern.rs:7:9 + | +LL | C | _ => {} + | ^ + +error: aborting due to previous error + From 1801841ae554a7778666c4c1085393b32eccf74d Mon Sep 17 00:00:00 2001 From: ThibsG Date: Tue, 26 May 2020 18:40:42 +0200 Subject: [PATCH 322/695] Add test cases for broader coverage --- clippy_lints/src/useless_conversion.rs | 10 ++++---- tests/ui/useless_conversion.stderr | 20 ++++++++-------- tests/ui/useless_conversion_try.rs | 8 +++++++ tests/ui/useless_conversion_try.stderr | 32 +++++++++++++++++++------- 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 1645c5777b26b..7fa97b2469912 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -71,7 +71,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "Useless conversion to the same type", + "useless conversion to the same type", "consider removing `.into()`", sugg, Applicability::MachineApplicable, // snippet @@ -87,7 +87,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "Useless conversion to the same type", + "useless conversion to the same type", "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet @@ -108,7 +108,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "Useless conversion to the same type", + "useless conversion to the same type", None, "consider removing `.try_into()`", ); @@ -139,7 +139,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "Useless conversion to the same type", + "useless conversion to the same type", None, &hint, ); @@ -158,7 +158,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "Useless conversion to the same type", + "useless conversion to the same type", &sugg_msg, sugg, Applicability::MachineApplicable, // snippet diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 0b2947f7d6282..84ec53702788c 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,4 +1,4 @@ -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:6:13 | LL | let _ = T::from(val); @@ -10,55 +10,55 @@ note: the lint level is defined here LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:7:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:19:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:51:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:52:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:53:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:54:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:55:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:56:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion.rs:57:21 | LL | let _: String = format!("Hello {}", "world").into(); diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index ab4f960edb7ef..3787ea991445c 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -31,4 +31,12 @@ fn main() { let _ = String::try_from("foo".to_string()).unwrap(); let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); let _: String = format!("Hello {}", "world").try_into().unwrap(); + let _: String = "".to_owned().try_into().unwrap(); + let _: String = match String::from("_").try_into() { + Ok(a) => a, + Err(_) => "".into(), + }; + // FIXME this is a false negative + #[allow(clippy::cmp_owned)] + if String::from("a") == TryInto::::try_into(String::from("a")).unwrap() {} } diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index 5afb5dc45d364..b765727c168f5 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -1,4 +1,4 @@ -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion_try.rs:6:13 | LL | let _ = T::try_from(val).unwrap(); @@ -11,7 +11,7 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: consider removing `T::try_from()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion_try.rs:7:5 | LL | val.try_into().unwrap() @@ -19,7 +19,7 @@ LL | val.try_into().unwrap() | = help: consider removing `.try_into()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion_try.rs:29:21 | LL | let _: String = "foo".to_string().try_into().unwrap(); @@ -27,7 +27,7 @@ LL | let _: String = "foo".to_string().try_into().unwrap(); | = help: consider removing `.try_into()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion_try.rs:30:21 | LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); @@ -35,7 +35,7 @@ LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); | = help: consider removing `TryFrom::try_from()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion_try.rs:31:13 | LL | let _ = String::try_from("foo".to_string()).unwrap(); @@ -43,7 +43,7 @@ LL | let _ = String::try_from("foo".to_string()).unwrap(); | = help: consider removing `String::try_from()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion_try.rs:32:13 | LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); @@ -51,7 +51,7 @@ LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); | = help: consider removing `String::try_from()` -error: Useless conversion to the same type +error: useless conversion to the same type --> $DIR/useless_conversion_try.rs:33:21 | LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); @@ -59,5 +59,21 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); | = help: consider removing `.try_into()` -error: aborting due to 7 previous errors +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:34:21 + | +LL | let _: String = "".to_owned().try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:35:27 + | +LL | let _: String = match String::from("_").try_into() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: aborting due to 9 previous errors From 1c30c9e92bdae1814dbae9367f214b4819cdd0de Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 26 May 2020 14:26:11 -0400 Subject: [PATCH 323/695] Don't bail out of trait selection when predicate references an error Fixes #72590 With PR #70551, observing a `ty::Error` guarantees that compilation is going to fail. Therefore, there are no soundness impliciations to continuing on when we encounter a `ty::Error` - we can only affect whether or not additional error messags are emitted. By not bailing out, we avoid incorrectly determining that types are `!Sized` when a type error is present, which allows us to avoid emitting additional spurious error messages. The original comment mentioned this code being shared by coherence - howver, this change resulted in no diagnostic changes in any of the existing tests. --- src/librustc_trait_selection/traits/select.rs | 11 -------- .../issue-72590-type-error-sized.rs | 22 +++++++++++++++ .../issue-72590-type-error-sized.stderr | 28 +++++++++++++++++++ 3 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/async-await/issue-72590-type-error-sized.rs create mode 100644 src/test/ui/async-await/issue-72590-type-error-sized.stderr diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 9b3381066a17b..32bd895f85162 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -1040,17 +1040,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if stack.obligation.predicate.references_error() { - // If we encounter a `Error`, we generally prefer the - // most "optimistic" result in response -- that is, the - // one least likely to report downstream errors. But - // because this routine is shared by coherence and by - // trait selection, there isn't an obvious "right" choice - // here in that respect, so we opt to just return - // ambiguity and let the upstream clients sort it out. - return Ok(None); - } - if let Some(conflict) = self.is_knowable(stack) { debug!("coherence stage: not knowable"); if self.intercrate_ambiguity_causes.is_some() { diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.rs b/src/test/ui/async-await/issue-72590-type-error-sized.rs new file mode 100644 index 0000000000000..00e098d43e073 --- /dev/null +++ b/src/test/ui/async-await/issue-72590-type-error-sized.rs @@ -0,0 +1,22 @@ +// Regression test for issue #72590 +// Tests that we don't emit a spurious "size cannot be statically determined" error +// edition:2018 + +struct Foo { + foo: Nonexistent, //~ ERROR cannot find + other: str +} + +struct Bar { + test: Missing //~ ERROR cannot find +} + +impl Foo { + async fn frob(self) {} //~ ERROR the size +} + +impl Bar { + async fn myfn(self) {} +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr new file mode 100644 index 0000000000000..603895b598c16 --- /dev/null +++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr @@ -0,0 +1,28 @@ +error[E0412]: cannot find type `Nonexistent` in this scope + --> $DIR/issue-72590-type-error-sized.rs:6:10 + | +LL | foo: Nonexistent, + | ^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/issue-72590-type-error-sized.rs:11:11 + | +LL | test: Missing + | ^^^^^^^ not found in this scope + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/issue-72590-type-error-sized.rs:15:19 + | +LL | async fn frob(self) {} + | ^^^^ doesn't have a size known at compile-time + | + = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `str` + = note: to learn more, visit + = note: required because it appears within the type `Foo` + = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0412. +For more information about an error, try `rustc --explain E0277`. From 7fd3bd0f57e11a65641501d6a898328ecb83ca77 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 24 Apr 2020 00:14:03 +0200 Subject: [PATCH 324/695] Register redundant_field_names and non_expressive_names as early passes --- clippy_lints/src/lib.rs | 12 ++++++------ src/driver.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 057d39d4c8252..902f3d56c1e4f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -346,13 +346,8 @@ mod reexport { /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. /// /// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &Conf) { +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { store.register_pre_expansion_pass(|| box write::Write::default()); - store.register_pre_expansion_pass(|| box redundant_field_names::RedundantFieldNames); - let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; - store.register_pre_expansion_pass(move || box non_expressive_names::NonExpressiveNames { - single_char_binding_names_threshold, - }); store.register_pre_expansion_pass(|| box attrs::EarlyAttributes); store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro); } @@ -1066,6 +1061,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); + store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); + let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; + store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { + single_char_binding_names_threshold, + }); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), diff --git a/src/driver.rs b/src/driver.rs index d3a7e24937f95..70c47b426825e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -79,7 +79,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { let conf = clippy_lints::read_conf(&[], &sess); clippy_lints::register_plugins(&mut lint_store, &sess, &conf); - clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf); + clippy_lints::register_pre_expansion_lints(&mut lint_store); clippy_lints::register_renamed(&mut lint_store); })); From 8e22d15055231fc0df4a07d57cd883fd89d8131b Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 12 May 2020 16:26:55 +0200 Subject: [PATCH 325/695] Fix fallout in redundant_field_names --- clippy_lints/src/redundant_field_names.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index b12c3c344ef4c..2a81170e49e75 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -2,6 +2,7 @@ use crate::utils::span_lint_and_sugg; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -36,6 +37,9 @@ declare_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if in_external_macro(cx.sess, expr.span) { + return; + } if let ExprKind::Struct(_, ref fields, _) = expr.kind { for field in fields { if field.is_shorthand { From 04db13eb564f6e3264a0d376ef95365b1de44797 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 12 May 2020 16:50:00 +0200 Subject: [PATCH 326/695] Fix fallout in similar_names --- clippy_lints/src/non_expressive_names.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 2b51b73207585..5328773a73899 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -5,6 +5,7 @@ use rustc_ast::ast::{ use rustc_ast::attr; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{Ident, SymbolStr}; @@ -354,12 +355,20 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { impl EarlyLintPass for NonExpressiveNames { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if in_external_macro(cx.sess, item.span) { + return; + } + if let ItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind { do_check(self, cx, &item.attrs, &sig.decl, blk); } } fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) { + if in_external_macro(cx.sess, item.span) { + return; + } + if let AssocItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind { do_check(self, cx, &item.attrs, &sig.decl, blk); } From b60fe399f3148c4af4ea568b262211661cab37ab Mon Sep 17 00:00:00 2001 From: philipp Date: Tue, 26 May 2020 21:38:44 +0200 Subject: [PATCH 327/695] Add remark regarding DoubleEndedIterator --- src/libcore/iter/traits/double_ended.rs | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/libcore/iter/traits/double_ended.rs b/src/libcore/iter/traits/double_ended.rs index cceb373d552a8..f6329c6c593ed 100644 --- a/src/libcore/iter/traits/double_ended.rs +++ b/src/libcore/iter/traits/double_ended.rs @@ -63,6 +63,32 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(None, iter.next()); /// assert_eq!(None, iter.next_back()); /// ``` + /// + /// # Remarks + /// + /// The elements yielded by `DoubleEndedIterator`'s methods may differ from + /// the ones yielded by `Iterator`'s methods: + /// + /// ``` + /// let vec = vec![(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b')]; + /// let uniq_by_fst_comp = || { + /// let mut seen = std::collections::HashSet::new(); + /// vec.iter().copied().filter(move |x| seen.insert(x.0)) + /// }; + /// + /// assert_eq!(uniq_by_fst_comp().last(), Some((2, 'a'))); + /// assert_eq!(uniq_by_fst_comp().next_back(), Some((2, 'b'))); + /// + /// assert_eq!( + /// uniq_by_fst_comp().fold(vec![], |mut v, x| {v.push(x); v}), + /// vec![(1, 'a'), (2, 'a')] + /// ); + /// assert_eq!( + /// uniq_by_fst_comp().rfold(vec![], |mut v, x| {v.push(x); v}), + /// vec![(2, 'b'), (1, 'c')] + /// ); + /// ``` + /// #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; From 6ddbef170bf0b79b868088580e28c862b691bff3 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Tue, 26 May 2020 23:06:46 +0300 Subject: [PATCH 328/695] Simplify suggestion --- src/librustc_typeck/check/callee.rs | 11 ++++------- src/test/ui/error-codes/E0040.stderr | 8 ++++---- src/test/ui/explicit/explicit-call-to-dtor.stderr | 8 ++++---- .../explicit/explicit-call-to-supertrait-dtor.stderr | 8 ++++---- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index a32174a83337d..f4e46a0493151 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -38,14 +38,11 @@ pub fn check_legal_trait_for_method_call( let suggestion = if snippet.is_empty() { "drop".to_string() } else { format!("drop({})", snippet) }; - let suggestion_span = - receiver.and_then(|s| tcx.sess.source_map().merge_spans(s, span)).unwrap_or(span); - err.span_suggestion( - suggestion_span, - "consider using `drop` function", - suggestion, - Applicability::MaybeIncorrect, + span, + &format!("consider using `drop` function: `{}`", suggestion), + String::new(), + Applicability::Unspecified, ); err.emit(); diff --git a/src/test/ui/error-codes/E0040.stderr b/src/test/ui/error-codes/E0040.stderr index 3b864d4ea4b2c..69cf28b29704f 100644 --- a/src/test/ui/error-codes/E0040.stderr +++ b/src/test/ui/error-codes/E0040.stderr @@ -2,10 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/E0040.rs:13:7 | LL | x.drop(); - | --^^^^ - | | | - | | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(x)` + | ^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(x)` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-dtor.stderr b/src/test/ui/explicit/explicit-call-to-dtor.stderr index 33ce235b30fda..5ebe4ee4b90f8 100644 --- a/src/test/ui/explicit/explicit-call-to-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-dtor.stderr @@ -2,10 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-dtor.rs:13:7 | LL | x.drop(); - | --^^^^ - | | | - | | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(x)` + | ^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(x)` error: aborting due to previous error diff --git a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr index 2e7bfac71cd32..cd3fb3119a5cf 100644 --- a/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/src/test/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -2,10 +2,10 @@ error[E0040]: explicit use of destructor method --> $DIR/explicit-call-to-supertrait-dtor.rs:17:14 | LL | self.drop(); - | -----^^^^ - | | | - | | explicit destructor calls not allowed - | help: consider using `drop` function: `drop(self)` + | ^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop(self)` error: aborting due to previous error From f384cdcbecf46db38e46177700d29e881dcb53b7 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Tue, 26 May 2020 16:52:16 -0400 Subject: [PATCH 329/695] improve error message for unexpected comma token in multiline block confusing diagnostics, issue #72253 add test for confusing error message, issue-72253 remove is_multiline check, refactor to self.expect(&token:Semi) update issue-72253 tests return Ok --- src/librustc_parse/parser/diagnostics.rs | 13 +++++++++++++ src/test/ui/issues/issue-72253.rs | 6 ++++++ src/test/ui/issues/issue-72253.stderr | 10 ++++++++++ 3 files changed, 29 insertions(+) create mode 100644 src/test/ui/issues/issue-72253.rs create mode 100644 src/test/ui/issues/issue-72253.stderr diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 93c7faf22a73f..079059ec75146 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -934,6 +934,19 @@ impl<'a> Parser<'a> { return self.expect(&token::Semi).map(drop); } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) { // The current token is in the same line as the prior token, not recoverable. + } else if [token::Comma, token::Colon].contains(&self.token.kind) + && &self.prev_token.kind == &token::CloseDelim(token::Paren) + { + // Likely typo: The current token is on a new line and is expected to be + // `.`, `;`, `?`, or an operator after a close delimiter token. + // + // let a = std::process::Command::new("echo") + // .arg("1") + // ,arg("2") + // ^ + // https://github.com/rust-lang/rust/issues/72253 + self.expect(&token::Semi)?; + return Ok(()); } else if self.look_ahead(1, |t| { t == &token::CloseDelim(token::Brace) || t.can_begin_expr() && t.kind != token::Colon }) && [token::Comma, token::Colon].contains(&self.token.kind) diff --git a/src/test/ui/issues/issue-72253.rs b/src/test/ui/issues/issue-72253.rs new file mode 100644 index 0000000000000..6f9af73b039e4 --- /dev/null +++ b/src/test/ui/issues/issue-72253.rs @@ -0,0 +1,6 @@ +fn main() { + let a = std::process::Command::new("echo") + .arg("1") + ,arg("2") //~ ERROR expected one of `.`, `;`, `?`, or an operator, found `,` + .output(); +} diff --git a/src/test/ui/issues/issue-72253.stderr b/src/test/ui/issues/issue-72253.stderr new file mode 100644 index 0000000000000..3819fd92a9e21 --- /dev/null +++ b/src/test/ui/issues/issue-72253.stderr @@ -0,0 +1,10 @@ +error: expected one of `.`, `;`, `?`, or an operator, found `,` + --> $DIR/issue-72253.rs:4:9 + | +LL | .arg("1") + | - expected one of `.`, `;`, `?`, or an operator +LL | ,arg("2") + | ^ unexpected token + +error: aborting due to previous error + From 0ad08109fd1c0b72d8bde3291271e4f2c8dbe66e Mon Sep 17 00:00:00 2001 From: Sora Morimoto Date: Wed, 27 May 2020 06:25:38 +0900 Subject: [PATCH 330/695] Bump actions/cache from v1 to v2 --- .github/workflows/clippy.yml | 2 +- .github/workflows/clippy_bors.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 8edf0c23860aa..5fa8009a8b42c 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -49,7 +49,7 @@ jobs: run: cargo update - name: Cache cargo dir - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cargo key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 6675a1029bbc8..a8a673343bf69 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -94,7 +94,7 @@ jobs: run: cargo update - name: Cache cargo dir - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cargo key: ${{ runner.os }}-${{ matrix.host }}-${{ hashFiles('Cargo.lock') }} @@ -190,7 +190,7 @@ jobs: run: cargo update - name: Cache cargo dir - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cargo key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} @@ -269,7 +269,7 @@ jobs: run: cargo update - name: Cache cargo dir - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cargo key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} From 416182347589e9503408136747593ff95fb9dd13 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Wed, 27 May 2020 00:06:50 +0200 Subject: [PATCH 331/695] Avoid triggering similar names on code from expansion --- clippy_lints/src/new_without_default.rs | 10 +++++----- clippy_lints/src/non_expressive_names.rs | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 3b88e4c4cb194..e556e5d59c188 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -90,8 +90,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { return; } if sig.decl.inputs.is_empty() && name == sym!(new) && cx.access_levels.is_reachable(id) { - let self_did = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); - let self_ty = cx.tcx.type_of(self_did); + let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); + let self_ty = cx.tcx.type_of(self_def_id); if_chain! { if same_tys(cx, self_ty, return_ty(cx, id)); if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); @@ -112,10 +112,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { // generics if_chain! { if let Some(ref impling_types) = self.impling_types; - if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def(); - if let Some(self_def_id) = self_def.did.as_local(); + if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def(); + if let Some(self_local_did) = self_def.did.as_local(); then { - let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_def_id); + let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); if impling_types.contains(&self_id) { return; } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 5328773a73899..5f14fe97afefa 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -132,7 +132,11 @@ struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { fn visit_pat(&mut self, pat: &'tcx Pat) { match pat.kind { - PatKind::Ident(_, ident, _) => self.check_ident(ident), + PatKind::Ident(_, ident, _) => { + if !pat.span.from_expansion() { + self.check_ident(ident); + } + }, PatKind::Struct(_, ref fields, _) => { for field in fields { if !field.is_shorthand { From 58429c74a31fabde8555f940530039bdadde8400 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 27 May 2020 00:51:08 +0200 Subject: [PATCH 332/695] Fail bors on missing changelog --- .github/workflows/clippy_bors.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 6675a1029bbc8..eb8da9dcc88a1 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -312,7 +312,7 @@ jobs: name: bors test finished if: github.event.pusher.name == 'bors' && success() runs-on: ubuntu-latest - needs: [base, integration] + needs: [changelog, base, integration_build, integration] steps: - name: Mark the job as successful @@ -322,7 +322,7 @@ jobs: name: bors test finished if: github.event.pusher.name == 'bors' && (failure() || cancelled()) runs-on: ubuntu-latest - needs: [base, integration] + needs: [changelog, base, integration_build, integration] steps: - name: Mark the job as a failure From 68bf8d2487103f90c0427701cf2247d758de9d13 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Tue, 26 May 2020 19:45:30 -0400 Subject: [PATCH 333/695] expand `env!` with def-site context --- src/librustc_builtin_macros/env.rs | 1 + src/test/ui/extenv/extenv-not-defined-custom.stderr | 2 ++ src/test/ui/extenv/extenv-not-defined-default.stderr | 2 ++ src/test/ui/extenv/issue-55897.stderr | 2 ++ src/test/ui/macros/macros-nonfatal-errors.stderr | 2 ++ 5 files changed, 9 insertions(+) diff --git a/src/librustc_builtin_macros/env.rs b/src/librustc_builtin_macros/env.rs index 21e1889513b01..d769ebb1f5520 100644 --- a/src/librustc_builtin_macros/env.rs +++ b/src/librustc_builtin_macros/env.rs @@ -77,6 +77,7 @@ pub fn expand_env<'cx>( return DummyResult::any(sp); } + let sp = cx.with_def_site_ctxt(sp); let e = match env::var(&*var.as_str()) { Err(_) => { cx.span_err(sp, &msg.as_str()); diff --git a/src/test/ui/extenv/extenv-not-defined-custom.stderr b/src/test/ui/extenv/extenv-not-defined-custom.stderr index 523982dd0196b..56415fd1f0dd0 100644 --- a/src/test/ui/extenv/extenv-not-defined-custom.stderr +++ b/src/test/ui/extenv/extenv-not-defined-custom.stderr @@ -3,6 +3,8 @@ error: my error message | LL | fn main() { env!("__HOPEFULLY_NOT_DEFINED__", "my error message"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/extenv/extenv-not-defined-default.stderr b/src/test/ui/extenv/extenv-not-defined-default.stderr index 4bfe330f59235..1a9332c4f1c9f 100644 --- a/src/test/ui/extenv/extenv-not-defined-default.stderr +++ b/src/test/ui/extenv/extenv-not-defined-default.stderr @@ -3,6 +3,8 @@ error: environment variable `__HOPEFULLY_NOT_DEFINED__` not defined | LL | env!("__HOPEFULLY_NOT_DEFINED__"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/extenv/issue-55897.stderr b/src/test/ui/extenv/issue-55897.stderr index c57a467cdba56..b62f06e33e531 100644 --- a/src/test/ui/extenv/issue-55897.stderr +++ b/src/test/ui/extenv/issue-55897.stderr @@ -3,6 +3,8 @@ error: environment variable `NON_EXISTENT` not defined | LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: suffixes on a string literal are invalid --> $DIR/issue-55897.rs:16:22 diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr index 6ef757a55b8fb..42954ebcdc1cd 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.stderr +++ b/src/test/ui/macros/macros-nonfatal-errors.stderr @@ -47,6 +47,8 @@ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: format argument must be a string literal --> $DIR/macros-nonfatal-errors.rs:23:13 From 822ad87325d6436a6aea5ae61ca34d9ad45dd839 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 17 May 2020 20:15:15 -0400 Subject: [PATCH 334/695] Add Peekable::next_if Prior art: `rust_analyzer` uses [`Parser::eat`](https://github.com/rust-analyzer/rust-analyzer/blob/50f4ae798b7c54d417ee88455b87fd0477473150/crates/ra_parser/src/parser.rs#L94), which is `next_if` specialized to `|y| next_if(|x| x == y)`. Basically every other parser I've run into in Rust has an equivalent of Parser::eat; see for example - [cranelift](https://github.com/bytecodealliance/wasmtime/blob/94190d57244b26baf36629c88104b0ba516510cf/cranelift/reader/src/parser.rs#L498) - [rcc](https://github.com/jyn514/rcc/blob/a8159c3904a0c950fbba817bf9109023fad69033/src/parse/mod.rs#L231) - [crunch](https://github.com/Kixiron/crunch-lang/blob/8521874fab8a7d62bfa7dea8bd1da94b63e31be8/crates/crunch-parser/src/parser/mod.rs#L213-L241) --- src/libcore/iter/adapters/mod.rs | 63 ++++++++++++++++++++++++++++++++ src/libcore/tests/iter.rs | 24 ++++++++++++ src/libcore/tests/lib.rs | 1 + 3 files changed, 88 insertions(+) diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index e9fc1b612dd39..3c6842b07b3bf 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -1574,6 +1574,69 @@ impl Peekable { let iter = &mut self.iter; self.peeked.get_or_insert_with(|| iter.next()).as_ref() } + + /// Consume the next value of this iterator if a condition is true. + /// + /// If `func` returns `true` for the next value of this iterator, consume and return it. + /// Otherwise, return `None`. + /// + /// # Examples + /// Consume a number if it's equal to 0. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (0..5).peekable(); + /// // The first item of the iterator is 0; consume it. + /// assert_eq!(iter.next_if(|&x| x == 0), Some(0)); + /// // The next item returned is now 1, so `consume` will return `false`. + /// assert_eq!(iter.next_if(|&x| x == 0), None); + /// // `next_if` saves the value of the next item if it was not equal to `expected`. + /// assert_eq!(iter.next(), Some(1)); + /// ``` + /// + /// Consume any number less than 10. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (1..20).peekable(); + /// // Consume all numbers less than 10 + /// while iter.next_if(|&x| x < 10).is_some() {} + /// // The next value returned will be 10 + /// assert_eq!(iter.next(), Some(10)); + /// ``` + #[unstable(feature = "peekable_next_if", issue = "72480")] + pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option { + match self.next() { + Some(matched) if func(&matched) => Some(matched), + other => { + // Since we called `self.next()`, we consumed `self.peeked`. + assert!(self.peeked.is_none()); + self.peeked = Some(other); + None + } + } + } + + /// Consume the next item if it is equal to `expected`. + /// + /// # Example + /// Consume a number if it's equal to 0. + /// ``` + /// #![feature(peekable_next_if)] + /// let mut iter = (0..5).peekable(); + /// // The first item of the iterator is 0; consume it. + /// assert_eq!(iter.next_if_eq(&0), Some(0)); + /// // The next item returned is now 1, so `consume` will return `false`. + /// assert_eq!(iter.next_if_eq(&0), None); + /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`. + /// assert_eq!(iter.next(), Some(1)); + /// ``` + #[unstable(feature = "peekable_next_if", issue = "72480")] + pub fn next_if_eq(&mut self, expected: &R) -> Option + where + R: ?Sized, + I::Item: PartialEq, + { + self.next_if(|next| next == expected) + } } /// An iterator that rejects elements while `predicate` returns `true`. diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 52cf068f0a567..0265235a65a35 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -813,6 +813,30 @@ fn test_iterator_peekable_rfold() { assert_eq!(i, xs.len()); } +#[test] +fn test_iterator_peekable_next_if_eq() { + // first, try on references + let xs = vec!["Heart", "of", "Gold"]; + let mut it = xs.into_iter().peekable(); + // try before `peek()` + assert_eq!(it.next_if_eq(&"trillian"), None); + assert_eq!(it.next_if_eq(&"Heart"), Some("Heart")); + // try after peek() + assert_eq!(it.peek(), Some(&"of")); + assert_eq!(it.next_if_eq(&"of"), Some("of")); + assert_eq!(it.next_if_eq(&"zaphod"), None); + // make sure `next()` still behaves + assert_eq!(it.next(), Some("Gold")); + + // make sure comparison works for owned values + let xs = vec![String::from("Ludicrous"), "speed".into()]; + let mut it = xs.into_iter().peekable(); + // make sure basic functionality works + assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into())); + assert_eq!(it.next_if_eq("speed"), Some("speed".into())); + assert_eq!(it.next_if_eq(""), None); +} + /// This is an iterator that follows the Iterator contract, /// but it is not fused. After having returned None once, it will start /// producing elements if .next() is called again. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index d636542d699f9..36dba6965fa24 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -44,6 +44,7 @@ #![feature(leading_trailing_ones)] #![feature(const_forget)] #![feature(option_unwrap_none)] +#![feature(peekable_next_if)] extern crate test; From 42ddcd3ec5bfb3004120d9f0114249526416d3cd Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Wed, 27 May 2020 16:16:27 +0800 Subject: [PATCH 335/695] Add myself to .mailmap --- .mailmap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mailmap b/.mailmap index 680aa04078f97..da17344c2085e 100644 --- a/.mailmap +++ b/.mailmap @@ -70,6 +70,8 @@ David Manescu David Ross Derek Chiang Derek Chiang (Enchi Jiang) Diggory Hardy Diggory Hardy +Donough Liu +Donough Liu DingMing Liu Dustin Bensing Dylan Braithwaite Dzmitry Malyshau From da18df285910446d5b4c212b96379e694f47533f Mon Sep 17 00:00:00 2001 From: Trevor Spiteri Date: Sun, 3 May 2020 15:17:45 +0200 Subject: [PATCH 336/695] doc: make impl block collapsible if it has an associated constant Fixes #71822. --- src/librustdoc/html/static/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 22c9426db2036..5b8c4890e8374 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2366,7 +2366,9 @@ function defocusSearchBar() { if (!next) { return; } - if (next.getElementsByClassName("method").length > 0 && hasClass(e, "impl")) { + if (hasClass(e, "impl") && + (next.getElementsByClassName("method").length > 0 || + next.getElementsByClassName("associatedconstant").length > 0)) { insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]); } }; From 3089c3b3077fa8ae0b6f68c5f56650bf726e3298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 27 May 2020 13:55:57 +0200 Subject: [PATCH 337/695] rustup https://github.com/rust-lang/rust/pull/72342, allow unused_crate_dependencies --- tests/ui/cognitive_complexity.rs | 2 +- tests/ui/cognitive_complexity_attr_used.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/cognitive_complexity.rs b/tests/ui/cognitive_complexity.rs index 1d3fe405521cd..912e6788afddc 100644 --- a/tests/ui/cognitive_complexity.rs +++ b/tests/ui/cognitive_complexity.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] #![warn(clippy::cognitive_complexity)] -#![allow(unused)] +#![allow(unused, unused_crate_dependencies)] #[rustfmt::skip] fn main() { diff --git a/tests/ui/cognitive_complexity_attr_used.rs b/tests/ui/cognitive_complexity_attr_used.rs index 403eff566ed6d..771a26fc9a86d 100644 --- a/tests/ui/cognitive_complexity_attr_used.rs +++ b/tests/ui/cognitive_complexity_attr_used.rs @@ -1,5 +1,5 @@ -#![warn(clippy::cognitive_complexity)] -#![warn(unused)] +#![warn(unused, clippy::cognitive_complexity)] +#![allow(unused_crate_dependencies)] fn main() { kaboom(); From 66e99849389475f1f425512278bfeddb25944deb Mon Sep 17 00:00:00 2001 From: Mikko Rantanen Date: Wed, 27 May 2020 16:21:30 +0300 Subject: [PATCH 338/695] Fix is_char_boundary documentation --- src/libcore/str/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index c517286d49898..faf2165d81301 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2270,12 +2270,11 @@ impl str { self.len() == 0 } - /// Checks that `index`-th byte lies at the start and/or end of a - /// UTF-8 code point sequence. + /// Checks that `index`-th byte is the first byte in a UTF-8 code point + /// sequence or the end of the string. /// /// The start and end of the string (when `index == self.len()`) are - /// considered to be - /// boundaries. + /// considered to be boundaries. /// /// Returns `false` if `index` is greater than `self.len()`. /// From 81f8ee458b10762e3c4b3389d373a5a26c1d8fb7 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 24 May 2020 12:18:22 +0100 Subject: [PATCH 339/695] Store `LocalDefId` directly in `rustc_resolve::Resolver` where possible This commit also include the following changes: * Remove unused `hir::Map::as_local_node_id` method * Remove outdated comment about `hir::Map::local_def_id` method * Remove confusing `GlobMap` type alias * Use `LocalDefId` instead of `DefId` in `extern_crate_map` * Use `LocalDefId` instead of `DefId` in `maybe_unused_extern_crates` * Modify `extern_mod_stmt_cnum` query to accept a `LocalDefId` instead of a `DefId` --- src/librustc_hir/hir.rs | 5 -- src/librustc_middle/hir/map/mod.rs | 6 -- src/librustc_middle/query/mod.rs | 6 +- src/librustc_middle/ty/context.rs | 4 +- src/librustc_middle/ty/mod.rs | 4 +- src/librustc_resolve/build_reduced_graph.rs | 13 +++-- src/librustc_resolve/check_unused.rs | 8 ++- src/librustc_resolve/late.rs | 3 +- src/librustc_resolve/lib.rs | 63 ++++++--------------- src/librustc_typeck/check_unused.rs | 11 ++-- 10 files changed, 44 insertions(+), 79 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index ef398ab25d3fb..35cff668581dd 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -10,7 +10,6 @@ pub use rustc_ast::ast::{CaptureBy, Movability, Mutability}; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::node_id::NodeMap; use rustc_ast::util::parser::ExprPrecedence; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_macros::HashStable_Generic; use rustc_span::source_map::{SourceMap, Spanned}; @@ -2664,10 +2663,6 @@ impl TraitCandidate { // Trait method resolution pub type TraitMap = NodeMap>>; -// Map from the NodeId of a glob import to a list of items which are actually -// imported. -pub type GlobMap = NodeMap>; - #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum Node<'hir> { Param(&'hir Param<'hir>), diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index b823516d64f3b..1e27f1549112a 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -169,7 +169,6 @@ impl<'hir> Map<'hir> { }) } - // FIXME(eddyb) this function can and should return `LocalDefId`. #[inline] pub fn local_def_id(&self, hir_id: HirId) -> LocalDefId { self.opt_local_def_id(hir_id).unwrap_or_else(|| { @@ -192,11 +191,6 @@ impl<'hir> Map<'hir> { self.tcx.definitions.opt_local_def_id(node) } - #[inline] - pub fn as_local_node_id(&self, def_id: DefId) -> Option { - self.tcx.definitions.as_local_node_id(def_id) - } - #[inline] pub fn as_local_hir_id(&self, def_id: LocalDefId) -> HirId { self.tcx.definitions.as_local_hir_id(def_id) diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 1083563c647b6..85451bf6538e4 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -973,7 +973,9 @@ rustc_queries! { desc { "fetching what a crate is named" } } query item_children(_: DefId) -> &'tcx [Export] {} - query extern_mod_stmt_cnum(_: DefId) -> Option {} + query extern_mod_stmt_cnum(_: LocalDefId) -> Option { + desc { "fetching extern module statement" } + } query get_lib_features(_: CrateNum) -> LibFeatures { storage(ArenaCacheSelector<'tcx>) @@ -1040,7 +1042,7 @@ rustc_queries! { desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) } } query maybe_unused_extern_crates(_: CrateNum) - -> &'tcx [(DefId, Span)] { + -> &'tcx [(LocalDefId, Span)] { eval_always desc { "looking up all possibly unused extern crates" } } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 5b53ab1778e3f..7a20014484190 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -925,7 +925,7 @@ pub struct GlobalCtxt<'tcx> { pub consts: CommonConsts<'tcx>, /// Resolutions of `extern crate` items produced by resolver. - extern_crate_map: FxHashMap, + extern_crate_map: FxHashMap, /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. @@ -944,7 +944,7 @@ pub struct GlobalCtxt<'tcx> { pub queries: query::Queries<'tcx>, maybe_unused_trait_imports: FxHashSet, - maybe_unused_extern_crates: Vec<(DefId, Span)>, + maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, /// A map of glob use to a set of names it actually imports. Currently only /// used in save-analysis. glob_map: FxHashMap>, diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index aad3c6889c3ce..85b5759e9936d 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -120,10 +120,10 @@ mod sty; pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box, - pub extern_crate_map: FxHashMap, + pub extern_crate_map: FxHashMap, pub trait_map: FxHashMap>>, pub maybe_unused_trait_imports: FxHashSet, - pub maybe_unused_extern_crates: Vec<(DefId, Span)>, + pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, pub export_map: ExportMap, pub glob_map: FxHashMap>, /// Extern prelude entries. The value is `true` if the entry was introduced diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index c32b823fe73b2..92ea119d9a458 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -130,7 +130,7 @@ impl<'a> Resolver<'a> { Some(def_id) => def_id, None => return self.ast_transform_scopes.get(&expn_id).unwrap_or(&self.graph_root), }; - if let Some(id) = self.definitions.as_local_node_id(def_id) { + if let Some(id) = def_id.as_local() { self.local_macro_def_scopes[&id] } else { let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); @@ -640,9 +640,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } else if orig_name == Some(kw::SelfLower) { self.r.graph_root } else { + let def_id = self.r.definitions.local_def_id(item.id); let crate_id = self.r.crate_loader.process_extern_crate(item, &self.r.definitions); - self.r.extern_crate_map.insert(item.id, crate_id); + self.r.extern_crate_map.insert(def_id, crate_id); self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) }; @@ -1173,10 +1174,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { _ => unreachable!(), }; - let def_id = self.r.definitions.local_def_id(item.id).to_def_id(); - let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id); - self.r.macro_map.insert(def_id, ext); - self.r.local_macro_def_scopes.insert(item.id, parent_scope.module); + let def_id = self.r.definitions.local_def_id(item.id); + let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id.to_def_id()); + self.r.macro_map.insert(def_id.to_def_id(), ext); + self.r.local_macro_def_scopes.insert(def_id, parent_scope.module); if macro_rules { let ident = ident.normalize_to_macros_2_0(); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index dd286723412dd..cc0e97aeb1430 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -64,8 +64,9 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { fn check_import(&mut self, id: ast::NodeId) { let mut used = false; self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns))); + let def_id = self.r.definitions.local_def_id(id); if !used { - if self.r.maybe_unused_trait_imports.contains(&id) { + if self.r.maybe_unused_trait_imports.contains(&def_id) { // Check later. return; } @@ -73,7 +74,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { } else { // This trait import is definitely used, in a way other than // method resolution. - self.r.maybe_unused_trait_imports.remove(&id); + self.r.maybe_unused_trait_imports.remove(&def_id); if let Some(i) = self.unused_imports.get_mut(&self.base_id) { i.unused.remove(&id); } @@ -245,7 +246,8 @@ impl Resolver<'_> { } } ImportKind::ExternCrate { .. } => { - self.maybe_unused_extern_crates.push((import.id, import.span)); + let def_id = self.definitions.local_def_id(import.id); + self.maybe_unused_extern_crates.push((def_id, import.span)); } ImportKind::MacroUse => { let msg = "unused `#[macro_use]` import"; diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 477e3be5cc2f8..f04813cf3bc7f 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -2209,7 +2209,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ) -> SmallVec<[NodeId; 1]> { let mut import_ids = smallvec![]; while let NameBindingKind::Import { import, binding, .. } = kind { - self.r.maybe_unused_trait_imports.insert(import.id); + let id = self.r.definitions.local_def_id(import.id); + self.r.maybe_unused_trait_imports.insert(id); self.r.add_to_glob_map(&import, trait_name); import_ids.push(import.id); kind = &binding.kind; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 63a4cdfbf2928..015f1b6315c19 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -37,7 +37,7 @@ use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::{DefKey, Definitions}; use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint}; -use rustc_hir::{GlobMap, TraitMap}; +use rustc_hir::TraitMap; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; @@ -866,7 +866,7 @@ pub struct Resolver<'a> { label_res_map: NodeMap, /// `CrateNum` resolutions of `extern crate` items. - extern_crate_map: NodeMap, + extern_crate_map: FxHashMap, export_map: ExportMap, trait_map: TraitMap, @@ -895,11 +895,11 @@ pub struct Resolver<'a> { underscore_disambiguator: u32, /// Maps glob imports to the names of items actually imported. - glob_map: GlobMap, + glob_map: FxHashMap>, used_imports: FxHashSet<(NodeId, Namespace)>, - maybe_unused_trait_imports: NodeSet, - maybe_unused_extern_crates: Vec<(NodeId, Span)>, + maybe_unused_trait_imports: FxHashSet, + maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, /// Privacy errors are delayed until the end in order to deduplicate them. privacy_errors: Vec>, @@ -924,7 +924,7 @@ pub struct Resolver<'a> { dummy_ext_bang: Lrc, dummy_ext_derive: Lrc, non_macro_attrs: [Lrc; 2], - local_macro_def_scopes: FxHashMap>, + local_macro_def_scopes: FxHashMap>, ast_transform_scopes: FxHashMap>, unused_macros: NodeMap, proc_macro_stubs: NodeSet, @@ -1269,11 +1269,7 @@ impl<'a> Resolver<'a> { pub fn into_outputs(self) -> ResolverOutputs { let definitions = self.definitions; - let extern_crate_map = self - .extern_crate_map - .into_iter() - .map(|(k, v)| (definitions.local_def_id(k).to_def_id(), v)) - .collect(); + let extern_crate_map = self.extern_crate_map; let export_map = self .export_map .into_iter() @@ -1298,21 +1294,9 @@ impl<'a> Resolver<'a> { ) }) .collect(); - let maybe_unused_trait_imports = self - .maybe_unused_trait_imports - .into_iter() - .map(|id| definitions.local_def_id(id)) - .collect(); - let maybe_unused_extern_crates = self - .maybe_unused_extern_crates - .into_iter() - .map(|(id, sp)| (definitions.local_def_id(id).to_def_id(), sp)) - .collect(); - let glob_map = self - .glob_map - .into_iter() - .map(|(id, names)| (definitions.local_def_id(id), names)) - .collect(); + let maybe_unused_trait_imports = self.maybe_unused_trait_imports; + let maybe_unused_extern_crates = self.maybe_unused_extern_crates; + let glob_map = self.glob_map; ResolverOutputs { definitions: definitions, cstore: Box::new(self.crate_loader.into_cstore()), @@ -1334,11 +1318,7 @@ impl<'a> Resolver<'a> { ResolverOutputs { definitions: self.definitions.clone(), cstore: Box::new(self.cstore().clone()), - extern_crate_map: self - .extern_crate_map - .iter() - .map(|(&k, &v)| (self.definitions.local_def_id(k).to_def_id(), v)) - .collect(), + extern_crate_map: self.extern_crate_map.clone(), export_map: self .export_map .iter() @@ -1366,21 +1346,9 @@ impl<'a> Resolver<'a> { ) }) .collect(), - glob_map: self - .glob_map - .iter() - .map(|(&id, names)| (self.definitions.local_def_id(id), names.clone())) - .collect(), - maybe_unused_trait_imports: self - .maybe_unused_trait_imports - .iter() - .map(|&id| self.definitions.local_def_id(id)) - .collect(), - maybe_unused_extern_crates: self - .maybe_unused_extern_crates - .iter() - .map(|&(id, sp)| (self.definitions.local_def_id(id).to_def_id(), sp)) - .collect(), + glob_map: self.glob_map.clone(), + maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), + maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(), extern_prelude: self .extern_prelude .iter() @@ -1522,7 +1490,8 @@ impl<'a> Resolver<'a> { #[inline] fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) { if import.is_glob() { - self.glob_map.entry(import.id).or_default().insert(ident.name); + let def_id = self.definitions.local_def_id(import.id); + self.glob_map.entry(def_id).or_default().insert(ident.name); } } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index dfe86aecbf727..eaaff70472bfb 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::TyCtxt; use rustc_session::lint; @@ -70,7 +70,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { // Collect first the crates that are completely unused. These we // can always suggest removing (no matter which edition we are // in). - let unused_extern_crates: FxHashMap = tcx + let unused_extern_crates: FxHashMap = tcx .maybe_unused_extern_crates(LOCAL_CRATE) .iter() .filter(|&&(def_id, _)| { @@ -88,7 +88,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { // Note that if we carry through to the `extern_mod_stmt_cnum` query // below it'll cause a panic because `def_id` is actually bogus at this // point in time otherwise. - if tcx.hir().find(tcx.hir().as_local_hir_id(def_id.expect_local())).is_none() { + if tcx.hir().find(tcx.hir().as_local_hir_id(def_id)).is_none() { return false; } true @@ -112,13 +112,14 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { }); for extern_crate in &crates_to_lint { - let id = tcx.hir().as_local_hir_id(extern_crate.def_id.expect_local()); + let def_id = extern_crate.def_id.expect_local(); + let id = tcx.hir().as_local_hir_id(def_id); let item = tcx.hir().expect_item(id); // If the crate is fully unused, we suggest removing it altogether. // We do this in any edition. if extern_crate.warn_if_unused { - if let Some(&span) = unused_extern_crates.get(&extern_crate.def_id) { + if let Some(&span) = unused_extern_crates.get(&def_id) { tcx.struct_span_lint_hir(lint, id, span, |lint| { // Removal suggestion span needs to include attributes (Issue #54400) let span_with_attrs = tcx From 709ddba9fea4a4ba84883793df4f63c2f64a690a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 27 May 2020 16:56:57 +0200 Subject: [PATCH 340/695] Allow types (with lifetimes/generics) in impl_lint_pass --- src/librustc_session/lint.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index b16d513d9239f..8a66fac1e3634 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -347,14 +347,14 @@ pub trait LintPass { fn name(&self) -> &'static str; } -/// Implements `LintPass for $name` with the given list of `Lint` statics. +/// Implements `LintPass for $ty` with the given list of `Lint` statics. #[macro_export] macro_rules! impl_lint_pass { - ($name:ident => [$($lint:expr),* $(,)?]) => { - impl $crate::lint::LintPass for $name { - fn name(&self) -> &'static str { stringify!($name) } + ($ty:ty => [$($lint:expr),* $(,)?]) => { + impl $crate::lint::LintPass for $ty { + fn name(&self) -> &'static str { stringify!($ty) } } - impl $name { + impl $ty { pub fn get_lints() -> $crate::lint::LintArray { $crate::lint_array!($($lint),*) } } }; From b12489248084f1ea33008e9b77ad2bbd41ee0f7f Mon Sep 17 00:00:00 2001 From: flip1995 Date: Wed, 27 May 2020 16:57:31 +0200 Subject: [PATCH 341/695] Add test for {impl,declare}_lint_pass macros --- src/test/ui-fulldeps/lint-pass-macros.rs | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/ui-fulldeps/lint-pass-macros.rs diff --git a/src/test/ui-fulldeps/lint-pass-macros.rs b/src/test/ui-fulldeps/lint-pass-macros.rs new file mode 100644 index 0000000000000..b3c2a542792f0 --- /dev/null +++ b/src/test/ui-fulldeps/lint-pass-macros.rs @@ -0,0 +1,26 @@ +// compile-flags: -Z unstable-options +// check-pass + +#![feature(rustc_private)] + +extern crate rustc_session; + +use rustc_session::lint::{LintArray, LintPass}; +use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; + +declare_lint! { + pub TEST_LINT, + Allow, + "test" +} + +struct Foo; + +struct Bar<'a>(&'a u32); + +impl_lint_pass!(Foo => [TEST_LINT]); +impl_lint_pass!(Bar<'_> => [TEST_LINT]); + +declare_lint_pass!(Baz => [TEST_LINT]); + +fn main() {} From 0c1ef853bb6ff87c2179b5e41b7e044b6c5b79cb Mon Sep 17 00:00:00 2001 From: Ivan Lozano Date: Tue, 26 May 2020 13:41:40 -0400 Subject: [PATCH 342/695] Add -Z profile-emit= for Gcov gcda output. Adds a -Z flag to control the file path that the Gcov gcda output is written to during runtime. This flag expects a path and filename, e.g. -Z profile-emit=gcov/out/lib.gcda. This works similar to GCC/Clang's -fprofile-dir flag which allows control over the output path for gcda coverage files. --- src/librustc_codegen_llvm/debuginfo/metadata.rs | 8 ++++---- src/librustc_interface/tests.rs | 1 + src/librustc_session/options.rs | 3 +++ src/test/run-make-fulldeps/profile/Makefile | 3 +++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 0cce0b25e5893..333eb805221ff 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -959,16 +959,16 @@ pub fn compile_unit_metadata( if tcx.sess.opts.debugging_opts.profile { let cu_desc_metadata = llvm::LLVMRustMetadataAsValue(debug_context.llcontext, unit_metadata); + let default_gcda_path = &tcx.output_filenames(LOCAL_CRATE).with_extension("gcda"); + let gcda_path = + tcx.sess.opts.debugging_opts.profile_emit.as_ref().unwrap_or(default_gcda_path); let gcov_cu_info = [ path_to_mdstring( debug_context.llcontext, &tcx.output_filenames(LOCAL_CRATE).with_extension("gcno"), ), - path_to_mdstring( - debug_context.llcontext, - &tcx.output_filenames(LOCAL_CRATE).with_extension("gcda"), - ), + path_to_mdstring(debug_context.llcontext, &gcda_path), cu_desc_metadata, ]; let gcov_metadata = llvm::LLVMMDNodeInContext( diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index d573e11fc4b24..91a4bc2b86856 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -557,6 +557,7 @@ fn test_debugging_options_tracking_hash() { tracked!(plt, Some(true)); tracked!(print_fuel, Some("abc".to_string())); tracked!(profile, true); + tracked!(profile_emit, Some(PathBuf::from("abc"))); tracked!(relro_level, Some(RelroLevel::Full)); tracked!(report_delayed_bugs, true); tracked!(run_dsymutil, false); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 95f9ff00fb8d4..a38e7f063d79a 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -955,6 +955,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print layout information for each type encountered (default: no)"), profile: bool = (false, parse_bool, [TRACKED], "insert profiling code (default: no)"), + profile_emit: Option = (None, parse_opt_pathbuf, [TRACKED], + "file path to emit profiling data at runtime when using 'profile' \ + (default based on relative source path)"), query_dep_graph: bool = (false, parse_bool, [UNTRACKED], "enable queries of the dependency graph for regression testing (default: no)"), query_stats: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/test/run-make-fulldeps/profile/Makefile b/src/test/run-make-fulldeps/profile/Makefile index c12712590e48f..04d382b475ed2 100644 --- a/src/test/run-make-fulldeps/profile/Makefile +++ b/src/test/run-make-fulldeps/profile/Makefile @@ -7,3 +7,6 @@ all: $(call RUN,test) || exit 1 [ -e "$(TMPDIR)/test.gcno" ] || (echo "No .gcno file"; exit 1) [ -e "$(TMPDIR)/test.gcda" ] || (echo "No .gcda file"; exit 1) + $(RUSTC) -g -Z profile -Z profile-emit=$(TMPDIR)/abc/abc.gcda test.rs + $(call RUN,test) || exit 1 + [ -e "$(TMPDIR)/abc/abc.gcda" ] || (echo "gcda file not emitted to defined path"; exit 1) From 593d1eed8216c4ab33500b323fbd1b3de4ecb34d Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Wed, 27 May 2020 14:09:54 -0400 Subject: [PATCH 343/695] improve diagnostics suggestion for missing `@` in slice id binding to rest pattern add issue 72373 tests fmt test fix suggestion format Replacement, not insertion of suggested string implement review changes refactor to span_suggestion_verbose, improve suggestion message, change id @ pattern space formatting fmt fix diagnostics spacing between ident and @ refactor reference --- src/librustc_parse/parser/mod.rs | 20 ++++++++++++++++++++ src/test/ui/issues/issue-72373.rs | 9 +++++++++ src/test/ui/issues/issue-72373.stderr | 13 +++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 src/test/ui/issues/issue-72373.rs create mode 100644 src/test/ui/issues/issue-72373.stderr diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index b21524cb9bdd2..c00b608482933 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -672,6 +672,26 @@ impl<'a> Parser<'a> { } } + // If this was a missing `@` in a binding pattern + // bail with a suggestion + // https://github.com/rust-lang/rust/issues/72373 + if self.prev_token.is_ident() && &self.token.kind == &token::DotDot { + let msg = format!( + "if you meant to bind the contents of \ + the rest of the array pattern into `{}`, use `@`", + pprust::token_to_string(&self.prev_token) + ); + expect_err + .span_suggestion_verbose( + self.prev_token.span.shrink_to_hi().until(self.token.span), + &msg, + " @ ".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + break; + } + // Attempt to keep parsing if it was an omitted separator. match f(self) { Ok(t) => { diff --git a/src/test/ui/issues/issue-72373.rs b/src/test/ui/issues/issue-72373.rs new file mode 100644 index 0000000000000..4da6061c27fe8 --- /dev/null +++ b/src/test/ui/issues/issue-72373.rs @@ -0,0 +1,9 @@ +fn foo(c: &[u32], n: u32) -> u32 { + match *c { + [h, ..] if h > n => 0, + [h, ..] if h == n => 1, + [h, ref ts..] => foo(c, n - h) + foo(ts, n), + //~^ ERROR expected one of `,`, `@`, `]`, or `|`, found `..` + [] => 0, + } +} diff --git a/src/test/ui/issues/issue-72373.stderr b/src/test/ui/issues/issue-72373.stderr new file mode 100644 index 0000000000000..dfde8624814f8 --- /dev/null +++ b/src/test/ui/issues/issue-72373.stderr @@ -0,0 +1,13 @@ +error: expected one of `,`, `@`, `]`, or `|`, found `..` + --> $DIR/issue-72373.rs:5:19 + | +LL | [h, ref ts..] => foo(c, n - h) + foo(ts, n), + | ^^ expected one of `,`, `@`, `]`, or `|` + | +help: if you meant to bind the contents of the rest of the array pattern into `ts`, use `@` + | +LL | [h, ref ts @ ..] => foo(c, n - h) + foo(ts, n), + | ^ + +error: aborting due to previous error + From 7b1187968ce5385758996ec7765d886d3a659d07 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 May 2020 20:31:17 +0200 Subject: [PATCH 344/695] expand unaligned_references test --- src/test/ui/lint/unaligned_references.rs | 15 +++++++--- src/test/ui/lint/unaligned_references.stderr | 30 +++++++++++++++----- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/test/ui/lint/unaligned_references.rs b/src/test/ui/lint/unaligned_references.rs index 1d9f4c3db2eb5..c4e5d065643c8 100644 --- a/src/test/ui/lint/unaligned_references.rs +++ b/src/test/ui/lint/unaligned_references.rs @@ -2,20 +2,27 @@ #[repr(packed)] pub struct Good { - data: &'static u32, - data2: [&'static u32; 2], + data: u64, + ptr: &'static u64, + data2: [u64; 2], aligned: [u8; 32], } fn main() { unsafe { - let good = Good { data: &0, data2: [&0, &0], aligned: [0; 32] }; + let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] }; + let _ = &good.ptr; //~ ERROR reference to packed field let _ = &good.data; //~ ERROR reference to packed field + // Error even when turned into raw pointer immediately. let _ = &good.data as *const _; //~ ERROR reference to packed field let _: *const _ = &good.data; //~ ERROR reference to packed field + // Error on method call. + let _ = good.data.clone(); //~ ERROR reference to packed field + // Error for nested fields. let _ = &good.data2[0]; //~ ERROR reference to packed field - let _ = &*good.data; // ok, behind a pointer + + let _ = &*good.ptr; // ok, behind a pointer let _ = &good.aligned; // ok, has align 1 let _ = &good.aligned[2]; // ok, has align 1 } diff --git a/src/test/ui/lint/unaligned_references.stderr b/src/test/ui/lint/unaligned_references.stderr index 0c594cdb30a3c..8786b9c05db27 100644 --- a/src/test/ui/lint/unaligned_references.stderr +++ b/src/test/ui/lint/unaligned_references.stderr @@ -1,8 +1,8 @@ error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:14:17 + --> $DIR/unaligned_references.rs:15:17 | -LL | let _ = &good.data; - | ^^^^^^^^^^ +LL | let _ = &good.ptr; + | ^^^^^^^^^ | note: the lint level is defined here --> $DIR/unaligned_references.rs:1:9 @@ -12,7 +12,15 @@ LL | #![deny(unaligned_references)] = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:15:17 + --> $DIR/unaligned_references.rs:16:17 + | +LL | let _ = &good.data; + | ^^^^^^^^^^ + | + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is unaligned + --> $DIR/unaligned_references.rs:18:17 | LL | let _ = &good.data as *const _; | ^^^^^^^^^^ @@ -20,7 +28,7 @@ LL | let _ = &good.data as *const _; = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:16:27 + --> $DIR/unaligned_references.rs:19:27 | LL | let _: *const _ = &good.data; | ^^^^^^^^^^ @@ -28,12 +36,20 @@ LL | let _: *const _ = &good.data; = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) error: reference to packed field is unaligned - --> $DIR/unaligned_references.rs:17:17 + --> $DIR/unaligned_references.rs:21:17 + | +LL | let _ = good.data.clone(); + | ^^^^^^^^^ + | + = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) + +error: reference to packed field is unaligned + --> $DIR/unaligned_references.rs:23:17 | LL | let _ = &good.data2[0]; | ^^^^^^^^^^^^^^ | = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors From a977df35d160c1fe7040c76a9276b64e7a7aedec Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 3 May 2020 23:11:34 +0200 Subject: [PATCH 345/695] Implement RFC 2585 --- src/librustc_feature/active.rs | 3 + src/librustc_middle/mir/mod.rs | 2 +- src/librustc_middle/mir/query.rs | 7 +++ src/librustc_mir/transform/check_unsafety.rs | 63 +++++++++++++++++--- src/librustc_mir_build/build/block.rs | 2 + src/librustc_session/lint/builtin.rs | 7 +++ src/librustc_span/symbol.rs | 1 + 7 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 90b2380d86450..fd35cb6c3f785 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -571,6 +571,9 @@ declare_features! ( /// Allows the use of `#[ffi_const]` on foreign functions. (active, ffi_const, "1.45.0", Some(58328), None), + /// No longer treat an unsafe function as an unsafe block. + (active, unsafe_block_in_unsafe_fn, "1.45.0", Some(71668), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index c279213e5bd0e..243f81459e760 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -408,7 +408,7 @@ impl<'tcx> Body<'tcx> { } } -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable, HashStable)] pub enum Safety { Safe, /// Unsafe because of a PushUnsafeBlock diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index 63b8d8c8da782..f19270e5561f0 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -15,10 +15,17 @@ use super::{Field, SourceInfo}; #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub enum UnsafetyViolationKind { + /// Only permitted in regular `fn`s, prohibitted in `const fn`s. General, /// Permitted both in `const fn`s and regular `fn`s. GeneralAndConstFn, + /// Borrow of packed field. + /// Has to be handled as a lint for backwards compatibility. BorrowPacked(hir::HirId), + /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. + /// Has to be handled as a lint for backwards compatibility. + /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`. + UnsafeFn(hir::HirId), } #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index a335fa2de411b..bcadbd091076a 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNUSED_UNSAFE}; +use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_span::symbol::{sym, Symbol}; use std::ops::Bound; @@ -351,14 +351,35 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { violation.kind = UnsafetyViolationKind::General; } } + UnsafetyViolationKind::UnsafeFn(_) => { + bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") + } + } + if !self.violations.contains(&violation) { + self.violations.push(violation) } + } + false + } + // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s + Safety::FnUnsafe if self.tcx.features().unsafe_block_in_unsafe_fn => { + for violation in violations { + let mut violation = *violation; + let lint_root = self.body.source_scopes[self.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + + // FIXME(LeSeulArtichaut): what to do with `UnsafetyViolationKind::BorrowPacked`? + violation.kind = UnsafetyViolationKind::UnsafeFn(lint_root); if !self.violations.contains(&violation) { self.violations.push(violation) } } false } - // `unsafe` function bodies allow unsafe without additional unsafe blocks + // `unsafe` function bodies allow unsafe without additional unsafe blocks (before RFC 2585) Safety::BuiltinUnsafe | Safety::FnUnsafe => true, Safety::ExplicitUnsafe(hir_id) => { // mark unsafe block as used if there are any unsafe operations inside @@ -383,6 +404,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { self.violations.push(violation) } } + UnsafetyViolationKind::UnsafeFn(_) => bug!( + "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" + ), } } } @@ -575,9 +599,12 @@ fn is_enclosed( kind: hir::ItemKind::Fn(ref sig, _, _), .. })) = tcx.hir().find(parent_id) { - match sig.header.unsafety { - hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)), - hir::Unsafety::Normal => None, + if sig.header.unsafety == hir::Unsafety::Unsafe + && !tcx.features().unsafe_block_in_unsafe_fn + { + Some(("fn".to_string(), parent_id)) + } else { + None } } else { is_enclosed(tcx, used_unsafe, parent_id) @@ -630,16 +657,20 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id.expect_local()); + let or_block_msg = if tcx.features().unsafe_block_in_unsafe_fn { "" } else { " or block" }; + for &UnsafetyViolation { source_info, description, details, kind } in violations.iter() { // Report an error. match kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { + // once struct_span_err!( tcx.sess, source_info.span, E0133, - "{} is unsafe and requires unsafe function or block", - description + "{} is unsafe and requires unsafe function{}", + description, + or_block_msg, ) .span_label(source_info.span, &*description.as_str()) .note(&details.as_str()) @@ -655,8 +686,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { source_info.span, |lint| { lint.build(&format!( - "{} is unsafe and requires unsafe function or block (error E0133)", - description + "{} is unsafe and requires unsafe function{} (error E0133)", + description, or_block_msg, )) .note(&details.as_str()) .emit() @@ -664,6 +695,20 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { ) } } + UnsafetyViolationKind::UnsafeFn(lint_hir_id) => tcx.struct_span_lint_hir( + UNSAFE_OP_IN_UNSAFE_FN, + lint_hir_id, + source_info.span, + |lint| { + lint.build(&format!( + "{} is unsafe and requires unsafe block (error E0133)", + description + )) + .span_label(source_info.span, &*description.as_str()) + .note(&details.as_str()) + .emit(); + }, + ), } } diff --git a/src/librustc_mir_build/build/block.rs b/src/librustc_mir_build/build/block.rs index fa783ddcf409a..b052c839152de 100644 --- a/src/librustc_mir_build/build/block.rs +++ b/src/librustc_mir_build/build/block.rs @@ -217,6 +217,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert_eq!(self.push_unsafe_count, 0); match self.unpushed_unsafe { Safety::Safe => {} + // no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585) + Safety::FnUnsafe if self.hir.tcx().features().unsafe_block_in_unsafe_fn => {} _ => return, } self.unpushed_unsafe = Safety::ExplicitUnsafe(hir_id); diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index e55ddc26a9441..7112ac35b082b 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -526,6 +526,12 @@ declare_lint! { "using only a subset of a register for inline asm inputs", } +declare_lint! { + pub UNSAFE_OP_IN_UNSAFE_FN, + Allow, + "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -597,6 +603,7 @@ declare_lint_pass! { SOFT_UNSTABLE, INLINE_NO_SANITIZE, ASM_SUB_REGISTER, + UNSAFE_OP_IN_UNSAFE_FN, ] } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 6a6098710e828..87952d409c896 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -806,6 +806,7 @@ symbols! { unmarked_api, unreachable_code, unrestricted_attribute_tokens, + unsafe_block_in_unsafe_fn, unsafe_no_drop_flag, unsized_locals, unsized_tuple_coercion, From 594c499db995abaacc10a74c0afbb9aeed48117d Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 3 May 2020 23:11:58 +0200 Subject: [PATCH 346/695] Add tests --- .../feature-gate-unsafe_block_in_unsafe_fn.rs | 11 +++++++ ...ture-gate-unsafe_block_in_unsafe_fn.stderr | 16 ++++++++++ .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 26 +++++++++++++++++ .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 29 +++++++++++++++++++ 4 files changed, 82 insertions(+) create mode 100644 src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs create mode 100644 src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr create mode 100644 src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs create mode 100644 src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs new file mode 100644 index 0000000000000..80005fd4ef632 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs @@ -0,0 +1,11 @@ +#![deny(unused_unsafe)] + +unsafe fn unsf() {} + +unsafe fn foo() { + unsafe { //~ ERROR unnecessary `unsafe` block + unsf() + } +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr new file mode 100644 index 0000000000000..64874e590fb89 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr @@ -0,0 +1,16 @@ +error: unnecessary `unsafe` block + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:6:5 + | +LL | unsafe fn foo() { + | --------------- because it's nested under this `unsafe` fn +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:9 + | +LL | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs new file mode 100644 index 0000000000000..0ffb2827bfde2 --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -0,0 +1,26 @@ +#![feature(unsafe_block_in_unsafe_fn)] +#![warn(unsafe_op_in_unsafe_fn)] +#![deny(unused_unsafe)] + +unsafe fn unsf() {} + +unsafe fn foo() { + unsf(); + //~^ WARNING call to unsafe function is unsafe and requires unsafe block +} + +unsafe fn bar() { + unsafe { unsf() } // no error +} + +unsafe fn baz() { + unsafe { unsafe { unsf() } } + //~^ ERROR unnecessary `unsafe` block +} + +#[allow(unsafe_op_in_unsafe_fn)] +unsafe fn qux() { + unsf(); // no error +} + +fn main() {} diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr new file mode 100644 index 0000000000000..be6af2a11c40a --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -0,0 +1,29 @@ +warning: call to unsafe function is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:8:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9 + | +LL | #![warn(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:14 + | +LL | unsafe { unsafe { unsf() } } + | ------ ^^^^^^ unnecessary `unsafe` block + | | + | because it's nested under this `unsafe` block + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:3:9 + | +LL | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + From bb6791502846b62e752c99396953e4db7739f28c Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 13 May 2020 23:43:21 +0200 Subject: [PATCH 347/695] Apply suggestions from code review --- src/librustc_lint/levels.rs | 19 +++++- src/librustc_middle/mir/query.rs | 5 +- src/librustc_mir/transform/check_unsafety.rs | 67 ++++++++++++------- src/librustc_mir_build/build/block.rs | 12 +++- .../feature-gate-unsafe_block_in_unsafe_fn.rs | 11 +-- ...ture-gate-unsafe_block_in_unsafe_fn.stderr | 36 +++++++--- .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 8 ++- .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 17 ++++- 8 files changed, 125 insertions(+), 50 deletions(-) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 274e57ae64cac..7069472015402 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -17,8 +17,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::lint::{builtin, Level, Lint}; use rustc_session::parse::feature_err; use rustc_session::Session; -use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP}; use std::cmp; @@ -80,6 +80,8 @@ impl<'s> LintLevelsBuilder<'s> { let level = cmp::min(level, self.sets.lint_cap); let lint_flag_val = Symbol::intern(lint_name); + self.check_gated_lint(lint_flag_val, DUMMY_SP); + let ids = match store.find_lints(&lint_name) { Ok(ids) => ids, Err(_) => continue, // errors handled in check_lint_name_cmdline above @@ -211,6 +213,7 @@ impl<'s> LintLevelsBuilder<'s> { let name = meta_item.path.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { + self.check_gated_lint(name, attr.span); let src = LintSource::Node(name, li.span(), reason); for id in ids { specs.insert(*id, (level, src)); @@ -383,6 +386,20 @@ impl<'s> LintLevelsBuilder<'s> { BuilderPush { prev, changed: prev != self.cur } } + fn check_gated_lint(&self, name: Symbol, span: Span) { + if name.as_str() == "unsafe_op_in_unsafe_fn" + && !self.sess.features_untracked().unsafe_block_in_unsafe_fn + { + feature_err( + &self.sess.parse_sess, + sym::unsafe_block_in_unsafe_fn, + span, + "the `unsafe_op_in_unsafe_fn` lint is unstable", + ) + .emit(); + } + } + /// Called after `push` when the scope of a set of attributes are exited. pub fn pop(&mut self, push: BuilderPush) { self.cur = push.prev; diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index f19270e5561f0..c63d7215867c2 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -21,16 +21,17 @@ pub enum UnsafetyViolationKind { GeneralAndConstFn, /// Borrow of packed field. /// Has to be handled as a lint for backwards compatibility. - BorrowPacked(hir::HirId), + BorrowPacked, /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. /// Has to be handled as a lint for backwards compatibility. /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`. - UnsafeFn(hir::HirId), + UnsafeFn, } #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] pub struct UnsafetyViolation { pub source_info: SourceInfo, + pub lint_root: hir::HirId, pub description: Symbol, pub details: Symbol, pub kind: UnsafetyViolationKind, diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index bcadbd091076a..0434f3447bced 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::hir_id::HirId; use rustc_hir::intravisit; use rustc_hir::Node; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; @@ -10,6 +11,7 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; +use rustc_session::lint::Level; use rustc_span::symbol::{sym, Symbol}; use std::ops::Bound; @@ -220,7 +222,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { for (i, elem) in place.projection.iter().enumerate() { let proj_base = &place.projection[..i]; - let old_source_info = self.source_info; + if context.is_borrow() { + if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { + self.require_unsafe( + "borrow of packed field", + "fields of packed structs might be misaligned: dereferencing a \ + misaligned pointer or even just creating a misaligned reference \ + is undefined behavior", + UnsafetyViolationKind::BorrowPacked, + ); + } + } + let source_info = self.source_info; if let [] = proj_base { let decl = &self.body.local_decls[place.local]; if decl.internal { @@ -301,7 +314,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } _ => {} } - self.source_info = old_source_info; + self.source_info = source_info; } } } @@ -314,9 +327,15 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { kind: UnsafetyViolationKind, ) { let source_info = self.source_info; + let lint_root = self.body.source_scopes[self.source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; self.register_violations( &[UnsafetyViolation { source_info, + lint_root, description: Symbol::intern(description), details: Symbol::intern(details), kind, @@ -343,7 +362,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { match violation.kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => {} - UnsafetyViolationKind::BorrowPacked(_) => { + UnsafetyViolationKind::BorrowPacked => { if self.min_const_fn { // const fns don't need to be backwards compatible and can // emit these violations as a hard error instead of a backwards @@ -351,7 +370,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { violation.kind = UnsafetyViolationKind::General; } } - UnsafetyViolationKind::UnsafeFn(_) => { + UnsafetyViolationKind::UnsafeFn => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } } @@ -365,14 +384,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { Safety::FnUnsafe if self.tcx.features().unsafe_block_in_unsafe_fn => { for violation in violations { let mut violation = *violation; - let lint_root = self.body.source_scopes[self.source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; // FIXME(LeSeulArtichaut): what to do with `UnsafetyViolationKind::BorrowPacked`? - violation.kind = UnsafetyViolationKind::UnsafeFn(lint_root); + violation.kind = UnsafetyViolationKind::UnsafeFn; if !self.violations.contains(&violation) { self.violations.push(violation) } @@ -394,7 +408,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { UnsafetyViolationKind::GeneralAndConstFn => {} // these things are forbidden in const fns UnsafetyViolationKind::General - | UnsafetyViolationKind::BorrowPacked(_) => { + | UnsafetyViolationKind::BorrowPacked => { let mut violation = *violation; // const fns don't need to be backwards compatible and can // emit these violations as a hard error instead of a backwards @@ -404,7 +418,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { self.violations.push(violation) } } - UnsafetyViolationKind::UnsafeFn(_) => bug!( + UnsafetyViolationKind::UnsafeFn => bug!( "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" ), } @@ -657,10 +671,13 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id.expect_local()); - let or_block_msg = if tcx.features().unsafe_block_in_unsafe_fn { "" } else { " or block" }; - - for &UnsafetyViolation { source_info, description, details, kind } in violations.iter() { + for &UnsafetyViolation { source_info, lint_root, description, details, kind } in + violations.iter() + { // Report an error. + let unsafe_fn_msg = + if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { "" } else { " function or" }; + match kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { // once @@ -668,26 +685,26 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { tcx.sess, source_info.span, E0133, - "{} is unsafe and requires unsafe function{}", + "{} is unsafe and requires unsafe{} block", description, - or_block_msg, + unsafe_fn_msg, ) .span_label(source_info.span, &*description.as_str()) .note(&details.as_str()) .emit(); } - UnsafetyViolationKind::BorrowPacked(lint_hir_id) => { + UnsafetyViolationKind::BorrowPacked => { if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) { tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id); } else { tcx.struct_span_lint_hir( SAFE_PACKED_BORROWS, - lint_hir_id, + lint_root, source_info.span, |lint| { lint.build(&format!( - "{} is unsafe and requires unsafe function{} (error E0133)", - description, or_block_msg, + "{} is unsafe and requires unsafe{} block (error E0133)", + description, unsafe_fn_msg, )) .note(&details.as_str()) .emit() @@ -695,9 +712,9 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { ) } } - UnsafetyViolationKind::UnsafeFn(lint_hir_id) => tcx.struct_span_lint_hir( + UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir( UNSAFE_OP_IN_UNSAFE_FN, - lint_hir_id, + lint_root, source_info.span, |lint| { lint.build(&format!( @@ -728,3 +745,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { report_unused_unsafe(tcx, &unsafe_used, block_id); } } + +fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool { + tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow +} diff --git a/src/librustc_mir_build/build/block.rs b/src/librustc_mir_build/build/block.rs index b052c839152de..4e4f0dc74cb7c 100644 --- a/src/librustc_mir_build/build/block.rs +++ b/src/librustc_mir_build/build/block.rs @@ -4,6 +4,8 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::hair::*; use rustc_hir as hir; use rustc_middle::mir::*; +use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; +use rustc_session::lint::Level; use rustc_span::Span; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -218,7 +220,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match self.unpushed_unsafe { Safety::Safe => {} // no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585) - Safety::FnUnsafe if self.hir.tcx().features().unsafe_block_in_unsafe_fn => {} + Safety::FnUnsafe + if self.hir.tcx().lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0 + != Level::Allow => {} _ => return, } self.unpushed_unsafe = Safety::ExplicitUnsafe(hir_id); @@ -233,7 +237,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .push_unsafe_count .checked_sub(1) .unwrap_or_else(|| span_bug!(span, "unsafe count underflow")); - if self.push_unsafe_count == 0 { Some(self.unpushed_unsafe) } else { None } + if self.push_unsafe_count == 0 { + Some(self.unpushed_unsafe) + } else { + None + } } }; diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs index 80005fd4ef632..bf33ac67fcae9 100644 --- a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs @@ -1,11 +1,4 @@ -#![deny(unused_unsafe)] - -unsafe fn unsf() {} - -unsafe fn foo() { - unsafe { //~ ERROR unnecessary `unsafe` block - unsf() - } -} +#![deny(unsafe_op_in_unsafe_fn)] +//~^ ERROR the `unsafe_op_in_unsafe_fn` lint is unstable fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr index 64874e590fb89..c5cad4a98d9ca 100644 --- a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.stderr @@ -1,16 +1,30 @@ -error: unnecessary `unsafe` block - --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:6:5 +error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1 | -LL | unsafe fn foo() { - | --------------- because it's nested under this `unsafe` fn -LL | unsafe { - | ^^^^^^ unnecessary `unsafe` block +LL | #![deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: the lint level is defined here - --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:9 + = note: see issue #71668 for more information + = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable + +error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1 + | +LL | #![deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #71668 for more information + = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable + +error[E0658]: the `unsafe_op_in_unsafe_fn` lint is unstable + --> $DIR/feature-gate-unsafe_block_in_unsafe_fn.rs:1:1 + | +LL | #![deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | #![deny(unused_unsafe)] - | ^^^^^^^^^^^^^ + = note: see issue #71668 for more information + = help: add `#![feature(unsafe_block_in_unsafe_fn)]` to the crate attributes to enable -error: aborting due to previous error +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 0ffb2827bfde2..7feb68b98577f 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -21,6 +21,12 @@ unsafe fn baz() { #[allow(unsafe_op_in_unsafe_fn)] unsafe fn qux() { unsf(); // no error + + unsafe { unsf() } + //~^ ERROR unnecessary `unsafe` block } -fn main() {} +fn main() { + unsf() + //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block +} diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr index be6af2a11c40a..e812210498c4c 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -25,5 +25,20 @@ note: the lint level is defined here LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ -error: aborting due to previous error; 1 warning emitted +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:5 + | +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5 + | +LL | unsf() + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 3 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0133`. From 3ce9d5c26982ff0516946dda7fa8d29580fa25b3 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 14 May 2020 20:37:23 +0200 Subject: [PATCH 348/695] Add more cases to the test --- .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 7feb68b98577f..618c911581597 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -1,16 +1,38 @@ #![feature(unsafe_block_in_unsafe_fn)] #![warn(unsafe_op_in_unsafe_fn)] #![deny(unused_unsafe)] +#![deny(safe_packed_borrows)] unsafe fn unsf() {} +const PTR: *const () = std::ptr::null(); +static mut VOID: () = (); + +#[repr(packed)] +pub struct Packed { + data: &'static u32, +} + +const PACKED: Packed = Packed { data: &0 }; unsafe fn foo() { unsf(); //~^ WARNING call to unsafe function is unsafe and requires unsafe block + *PTR; + //~^ WARNING dereference of raw pointer is unsafe and requires unsafe block + VOID = (); + //~^ WARNING use of mutable static is unsafe and requires unsafe block + &PACKED.data; // the level for the `safe_packed_borrows` lint is ignored + //~^ WARNING borrow of packed field is unsafe and requires unsafe block } unsafe fn bar() { - unsafe { unsf() } // no error + // no error + unsafe { + unsf(); + *PTR; + VOID = (); + &PACKED.data; + } } unsafe fn baz() { @@ -20,7 +42,11 @@ unsafe fn baz() { #[allow(unsafe_op_in_unsafe_fn)] unsafe fn qux() { - unsf(); // no error + // lint allowed -> no error + unsf(); + *PTR; + VOID = (); + &PACKED.data; unsafe { unsf() } //~^ ERROR unnecessary `unsafe` block From b3e012becc6539de9570eee6ce694f07879935d2 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 19 May 2020 00:18:50 +0200 Subject: [PATCH 349/695] Fix inverted `if` condition --- src/librustc_mir/transform/check_unsafety.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 0434f3447bced..3cff214f441c0 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -676,7 +676,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { { // Report an error. let unsafe_fn_msg = - if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { "" } else { " function or" }; + if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" }; match kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { From a41f76321a05ce7941d843dc18ea11f7c8a11c6f Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 19 May 2020 00:19:31 +0200 Subject: [PATCH 350/695] Use the lowest of `unsafe_op_in_unsafe_fn` and `safe_borrow_packed` for packed borrows in unsafe fns --- src/librustc_middle/mir/query.rs | 4 +++ src/librustc_mir/transform/check_unsafety.rs | 33 +++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index c63d7215867c2..99bfb74c243b4 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -26,6 +26,10 @@ pub enum UnsafetyViolationKind { /// Has to be handled as a lint for backwards compatibility. /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`. UnsafeFn, + /// Borrow of packed field in an `unsafe fn` but outside an `unsafe` block. + /// Has to be handled as a lint for backwards compatibility. + /// Should stay gated under `#![feature(unsafe_block_in_unsafe_fn)]`. + UnsafeFnBorrowPacked, } #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, HashStable)] diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 3cff214f441c0..177efa2fc0d6c 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -370,7 +370,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { violation.kind = UnsafetyViolationKind::General; } } - UnsafetyViolationKind::UnsafeFn => { + UnsafetyViolationKind::UnsafeFn + | UnsafetyViolationKind::UnsafeFnBorrowPacked => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } } @@ -385,8 +386,11 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { for violation in violations { let mut violation = *violation; - // FIXME(LeSeulArtichaut): what to do with `UnsafetyViolationKind::BorrowPacked`? - violation.kind = UnsafetyViolationKind::UnsafeFn; + if violation.kind == UnsafetyViolationKind::BorrowPacked { + violation.kind = UnsafetyViolationKind::UnsafeFnBorrowPacked; + } else { + violation.kind = UnsafetyViolationKind::UnsafeFn; + } if !self.violations.contains(&violation) { self.violations.push(violation) } @@ -418,7 +422,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { self.violations.push(violation) } } - UnsafetyViolationKind::UnsafeFn => bug!( + UnsafetyViolationKind::UnsafeFn + | UnsafetyViolationKind::UnsafeFnBorrowPacked => bug!( "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" ), } @@ -719,13 +724,31 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { |lint| { lint.build(&format!( "{} is unsafe and requires unsafe block (error E0133)", - description + description, )) .span_label(source_info.span, &*description.as_str()) .note(&details.as_str()) .emit(); }, ), + UnsafetyViolationKind::UnsafeFnBorrowPacked => { + let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0 + <= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0 + { + SAFE_PACKED_BORROWS + } else { + UNSAFE_OP_IN_UNSAFE_FN + }; + tcx.struct_span_lint_hir(&lint, lint_root, source_info.span, |lint| { + lint.build(&format!( + "{} is unsafe and requires unsafe block (error E0133)", + description, + )) + .span_label(source_info.span, &*description.as_str()) + .note(&details.as_str()) + .emit(); + }) + } } } From a3bae5ce73a65671ee35037ac988766973628295 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 19 May 2020 12:16:40 +0200 Subject: [PATCH 351/695] Fix wrong conflict resolution --- src/librustc_mir/transform/check_unsafety.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 177efa2fc0d6c..7be640ae24310 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -204,18 +204,12 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { - let source_info = self.source_info; - let lint_root = self.body.source_scopes[source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; self.require_unsafe( "borrow of packed field", "fields of packed structs might be misaligned: dereferencing a \ misaligned pointer or even just creating a misaligned reference \ is undefined behavior", - UnsafetyViolationKind::BorrowPacked(lint_root), + UnsafetyViolationKind::BorrowPacked, ); } } From 925d5ac45f4a44dd61f1ebd4b7bd3cc89fcb2b5f Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 21 May 2020 23:53:12 +0200 Subject: [PATCH 352/695] Fix and bless tests --- .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 71 +++++++++-- .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 118 ++++++++++++++++-- 2 files changed, 168 insertions(+), 21 deletions(-) diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 618c911581597..6dfb97c230d66 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -1,5 +1,5 @@ #![feature(unsafe_block_in_unsafe_fn)] -#![warn(unsafe_op_in_unsafe_fn)] +#![deny(unsafe_op_in_unsafe_fn)] #![deny(unused_unsafe)] #![deny(safe_packed_borrows)] @@ -14,18 +14,34 @@ pub struct Packed { const PACKED: Packed = Packed { data: &0 }; -unsafe fn foo() { +unsafe fn deny_level() { unsf(); - //~^ WARNING call to unsafe function is unsafe and requires unsafe block + //~^ ERROR call to unsafe function is unsafe and requires unsafe block *PTR; - //~^ WARNING dereference of raw pointer is unsafe and requires unsafe block + //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block VOID = (); - //~^ WARNING use of mutable static is unsafe and requires unsafe block - &PACKED.data; // the level for the `safe_packed_borrows` lint is ignored - //~^ WARNING borrow of packed field is unsafe and requires unsafe block + //~^ ERROR use of mutable static is unsafe and requires unsafe block + &PACKED.data; + //~^ ERROR borrow of packed field is unsafe and requires unsafe block + //~| WARNING this was previously accepted by the compiler but is being phased out } -unsafe fn bar() { +// Check that `unsafe_op_in_unsafe_fn` works starting from the `warn` level. +#[warn(unsafe_op_in_unsafe_fn)] +#[deny(warnings)] +unsafe fn warning_level() { + unsf(); + //~^ ERROR call to unsafe function is unsafe and requires unsafe block + *PTR; + //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block + VOID = (); + //~^ ERROR use of mutable static is unsafe and requires unsafe block + &PACKED.data; + //~^ ERROR borrow of packed field is unsafe and requires unsafe block + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +unsafe fn explicit_block() { // no error unsafe { unsf(); @@ -35,13 +51,25 @@ unsafe fn bar() { } } -unsafe fn baz() { +unsafe fn two_explicit_blocks() { unsafe { unsafe { unsf() } } //~^ ERROR unnecessary `unsafe` block } +#[warn(safe_packed_borrows)] +unsafe fn warn_packed_borrows() { + &PACKED.data; + //~^ WARNING borrow of packed field is unsafe and requires unsafe block + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +#[allow(safe_packed_borrows)] +unsafe fn allow_packed_borrows() { + &PACKED.data; // `safe_packed_borrows` is allowed, no error +} + #[allow(unsafe_op_in_unsafe_fn)] -unsafe fn qux() { +unsafe fn allow_level() { // lint allowed -> no error unsf(); *PTR; @@ -52,7 +80,26 @@ unsafe fn qux() { //~^ ERROR unnecessary `unsafe` block } +unsafe fn nested_allow_level() { + #[allow(unsafe_op_in_unsafe_fn)] + { + // lint allowed -> no error + unsf(); + *PTR; + VOID = (); + &PACKED.data; + + unsafe { unsf() } + //~^ ERROR unnecessary `unsafe` block + } +} + fn main() { - unsf() - //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block + unsf(); + //~^ ERROR call to unsafe function is unsafe and requires unsafe block + #[allow(unsafe_op_in_unsafe_fn)] + { + unsf(); + //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block + } } diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr index e812210498c4c..efc53f0b28b29 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -1,5 +1,5 @@ -warning: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:8:5 +error: call to unsafe function is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:18:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -7,12 +7,83 @@ LL | unsf(); note: the lint level is defined here --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9 | -LL | #![warn(unsafe_op_in_unsafe_fn)] +LL | #![deny(unsafe_op_in_unsafe_fn)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: consult the function's documentation for information on how to avoid undefined behavior +error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:5 + | +LL | *PTR; + | ^^^^ dereference of raw pointer + | + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: use of mutable static is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5 + | +LL | VOID = (); + | ^^^^^^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9 + | +LL | #![deny(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = 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 #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: call to unsafe function is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:8 + | +LL | #[deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]` + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:35:5 + | +LL | *PTR; + | ^^^^ dereference of raw pointer + | + = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: use of mutable static is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:37:5 + | +LL | VOID = (); + | ^^^^^^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:39:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | + = 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 #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:17:14 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:14 | LL | unsafe { unsafe { unsf() } } | ------ ^^^^^^ unnecessary `unsafe` block @@ -25,20 +96,49 @@ note: the lint level is defined here LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ +warning: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:61:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:59:8 + | +LL | #[warn(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = 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 #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:79:5 | LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5 +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:92:9 | -LL | unsf() +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error[E0133]: call to unsafe function is unsafe and requires unsafe block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:98:5 + | +LL | unsf(); | ^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 3 previous errors; 1 warning emitted +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:102:9 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 13 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0133`. From 9671b44609d2adbf041fcc5f8b63183786417ba7 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 22 May 2020 20:21:26 +0200 Subject: [PATCH 353/695] Add tests for packed borrows in unsafe fns --- ...c-2585-safe_packed_borrows-in-unsafe-fn.rs | 67 +++++++++++++++++++ ...85-safe_packed_borrows-in-unsafe-fn.stderr | 60 +++++++++++++++++ .../unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs | 29 -------- .../rfc-2585-unsafe_op_in_unsafe_fn.stderr | 66 ++++-------------- 4 files changed, 140 insertions(+), 82 deletions(-) create mode 100644 src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs create mode 100644 src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr diff --git a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs new file mode 100644 index 0000000000000..540612a7dce05 --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs @@ -0,0 +1,67 @@ +#![feature(unsafe_block_in_unsafe_fn)] + +#[repr(packed)] +pub struct Packed { + data: &'static u32, +} + +const PACKED: Packed = Packed { data: &0 }; + +#[allow(safe_packed_borrows)] +#[allow(unsafe_op_in_unsafe_fn)] +unsafe fn allow_allow() { + &PACKED.data; // allowed +} + +#[allow(safe_packed_borrows)] +#[warn(unsafe_op_in_unsafe_fn)] +unsafe fn allow_warn() { + &PACKED.data; // allowed +} + +#[allow(safe_packed_borrows)] +#[deny(unsafe_op_in_unsafe_fn)] +unsafe fn allow_deny() { + &PACKED.data; // allowed +} + +#[warn(safe_packed_borrows)] +#[allow(unsafe_op_in_unsafe_fn)] +unsafe fn warn_allow() { + &PACKED.data; // allowed +} + +#[warn(safe_packed_borrows)] +#[warn(unsafe_op_in_unsafe_fn)] +unsafe fn warn_warn() { + &PACKED.data; //~ WARN + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +#[warn(safe_packed_borrows)] +#[deny(unsafe_op_in_unsafe_fn)] +unsafe fn warn_deny() { + &PACKED.data; //~ WARN + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +#[deny(safe_packed_borrows)] +#[allow(unsafe_op_in_unsafe_fn)] +unsafe fn deny_allow() { + &PACKED.data; // allowed +} + +#[deny(safe_packed_borrows)] +#[warn(unsafe_op_in_unsafe_fn)] +unsafe fn deny_warn() { + &PACKED.data; //~ WARN +} + +#[deny(safe_packed_borrows)] +#[deny(unsafe_op_in_unsafe_fn)] +unsafe fn deny_deny() { + &PACKED.data; //~ ERROR + //~| WARNING this was previously accepted by the compiler but is being phased out +} + +fn main() {} diff --git a/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr new file mode 100644 index 0000000000000..fda15159643b6 --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-safe_packed_borrows-in-unsafe-fn.stderr @@ -0,0 +1,60 @@ +warning: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:37:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:34:8 + | +LL | #[warn(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = 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 #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +warning: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:44:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:41:8 + | +LL | #[warn(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = 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 #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +warning: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:57:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:55:8 + | +LL | #[warn(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: borrow of packed field is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:63:5 + | +LL | &PACKED.data; + | ^^^^^^^^^^^^ borrow of packed field + | +note: the lint level is defined here + --> $DIR/rfc-2585-safe_packed_borrows-in-unsafe-fn.rs:60:8 + | +LL | #[deny(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = 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 #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: aborting due to previous error; 3 warnings emitted + diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index 6dfb97c230d66..1e57b03ced48b 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -1,19 +1,11 @@ #![feature(unsafe_block_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(unused_unsafe)] -#![deny(safe_packed_borrows)] unsafe fn unsf() {} const PTR: *const () = std::ptr::null(); static mut VOID: () = (); -#[repr(packed)] -pub struct Packed { - data: &'static u32, -} - -const PACKED: Packed = Packed { data: &0 }; - unsafe fn deny_level() { unsf(); //~^ ERROR call to unsafe function is unsafe and requires unsafe block @@ -21,9 +13,6 @@ unsafe fn deny_level() { //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block VOID = (); //~^ ERROR use of mutable static is unsafe and requires unsafe block - &PACKED.data; - //~^ ERROR borrow of packed field is unsafe and requires unsafe block - //~| WARNING this was previously accepted by the compiler but is being phased out } // Check that `unsafe_op_in_unsafe_fn` works starting from the `warn` level. @@ -36,9 +25,6 @@ unsafe fn warning_level() { //~^ ERROR dereference of raw pointer is unsafe and requires unsafe block VOID = (); //~^ ERROR use of mutable static is unsafe and requires unsafe block - &PACKED.data; - //~^ ERROR borrow of packed field is unsafe and requires unsafe block - //~| WARNING this was previously accepted by the compiler but is being phased out } unsafe fn explicit_block() { @@ -47,7 +33,6 @@ unsafe fn explicit_block() { unsf(); *PTR; VOID = (); - &PACKED.data; } } @@ -56,25 +41,12 @@ unsafe fn two_explicit_blocks() { //~^ ERROR unnecessary `unsafe` block } -#[warn(safe_packed_borrows)] -unsafe fn warn_packed_borrows() { - &PACKED.data; - //~^ WARNING borrow of packed field is unsafe and requires unsafe block - //~| WARNING this was previously accepted by the compiler but is being phased out -} - -#[allow(safe_packed_borrows)] -unsafe fn allow_packed_borrows() { - &PACKED.data; // `safe_packed_borrows` is allowed, no error -} - #[allow(unsafe_op_in_unsafe_fn)] unsafe fn allow_level() { // lint allowed -> no error unsf(); *PTR; VOID = (); - &PACKED.data; unsafe { unsf() } //~^ ERROR unnecessary `unsafe` block @@ -87,7 +59,6 @@ unsafe fn nested_allow_level() { unsf(); *PTR; VOID = (); - &PACKED.data; unsafe { unsf() } //~^ ERROR unnecessary `unsafe` block diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr index efc53f0b28b29..cc595df12cc44 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr @@ -1,5 +1,5 @@ error: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:18:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:10:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -12,7 +12,7 @@ LL | #![deny(unsafe_op_in_unsafe_fn)] = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -20,36 +20,21 @@ LL | *PTR; = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | -note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9 - | -LL | #![deny(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ - = 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 #46043 - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:5 | LL | unsf(); | ^^^^^^ call to unsafe function | note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:8 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:20:8 | LL | #[deny(warnings)] | ^^^^^^^^ @@ -57,7 +42,7 @@ LL | #[deny(warnings)] = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:35:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -65,25 +50,15 @@ LL | *PTR; = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:37:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static | = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior -error: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:39:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | - = 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 #46043 - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:14 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:40:14 | LL | unsafe { unsafe { unsf() } } | ------ ^^^^^^ unnecessary `unsafe` block @@ -96,35 +71,20 @@ note: the lint level is defined here LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ -warning: borrow of packed field is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:61:5 - | -LL | &PACKED.data; - | ^^^^^^^^^^^^ borrow of packed field - | -note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:59:8 - | -LL | #[warn(safe_packed_borrows)] - | ^^^^^^^^^^^^^^^^^^^ - = 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 #46043 - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:79:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:51:5 | LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:92:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:63:9 | LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error[E0133]: call to unsafe function is unsafe and requires unsafe block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:98:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:69:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -132,13 +92,13 @@ LL | unsf(); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:102:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:9 | LL | unsf(); | ^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 13 previous errors; 1 warning emitted +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0133`. From 3599ada976568d0b5326e890d4b0c2f22dcdc985 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 22:15:14 +0200 Subject: [PATCH 354/695] Mark deduplicated errors as expected in gate test --- .../ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs index bf33ac67fcae9..61e512a12a18d 100644 --- a/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs +++ b/src/test/ui/feature-gates/feature-gate-unsafe_block_in_unsafe_fn.rs @@ -1,4 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] //~^ ERROR the `unsafe_op_in_unsafe_fn` lint is unstable +//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable +//~| ERROR the `unsafe_op_in_unsafe_fn` lint is unstable fn main() {} From 4a538d31e056c7563d7e29a6bc7c89e9e46d8ee8 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 22:22:01 +0200 Subject: [PATCH 355/695] Do not hardcode lint name --- src/librustc_lint/levels.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 7069472015402..2e3fc162b530f 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -9,6 +9,7 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::{intravisit, HirId}; +use rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_middle::hir::map::Map; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; @@ -387,7 +388,7 @@ impl<'s> LintLevelsBuilder<'s> { } fn check_gated_lint(&self, name: Symbol, span: Span) { - if name.as_str() == "unsafe_op_in_unsafe_fn" + if name.as_str() == UNSAFE_OP_IN_UNSAFE_FN.name && !self.sess.features_untracked().unsafe_block_in_unsafe_fn { feature_err( From e3d27ec1c82e223277b16f30e2355056144ca0da Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 22:32:40 +0200 Subject: [PATCH 356/695] Add explanation about taking the minimum of the two lints --- src/librustc_mir/transform/check_unsafety.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 7be640ae24310..1f01bc0e19513 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -726,6 +726,17 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { }, ), UnsafetyViolationKind::UnsafeFnBorrowPacked => { + // When `unsafe_op_in_unsafe_fn` is disallowed, the behavior of safe and unsafe functions + // should be the same in terms of warnings and errors. Therefore, with `#[warn(safe_packed_borrows)]`, + // a safe packed borrow should emit a warning *but not an error* in an unsafe function, + // just like in a safe function, even if `unsafe_op_in_unsafe_fn` is `deny`. + // + // Also, `#[warn(unsafe_op_in_unsafe_fn)]` can't cause any new errors. Therefore, with + // `#[deny(safe_packed_borrows)]` and `#[warn(unsafe_op_in_unsafe_fn)]`, a packed borrow + // should only issue a warning for the sake of backwards compatibility. + // + // The solution those 2 expectations is to always take the minimum of both lints. + // This prevent any new errors (unless both lints are explicitely set to `deny`). let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0 <= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0 { From 1b0885062266a21e67fdeb12320c92ac7c00742e Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 22:39:07 +0200 Subject: [PATCH 357/695] Fix import --- src/librustc_lint/levels.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 2e3fc162b530f..8dd683ae7995d 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -9,7 +9,6 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::{intravisit, HirId}; -use rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_middle::hir::map::Map; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; @@ -388,7 +387,7 @@ impl<'s> LintLevelsBuilder<'s> { } fn check_gated_lint(&self, name: Symbol, span: Span) { - if name.as_str() == UNSAFE_OP_IN_UNSAFE_FN.name + if name.as_str() == builtin::UNSAFE_OP_IN_UNSAFE_FN.name && !self.sess.features_untracked().unsafe_block_in_unsafe_fn { feature_err( From 63066c0c06de27bc84f7fbbe683b59d4cb0441db Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 23 May 2020 23:11:55 +0200 Subject: [PATCH 358/695] Use `LintId`s to check for gated lints --- src/librustc_lint/levels.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 8dd683ae7995d..3d2ddf12a0a1f 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -14,7 +14,7 @@ use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::{builtin, Level, Lint}; +use rustc_session::lint::{builtin, Level, Lint, LintId}; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; @@ -80,13 +80,13 @@ impl<'s> LintLevelsBuilder<'s> { let level = cmp::min(level, self.sets.lint_cap); let lint_flag_val = Symbol::intern(lint_name); - self.check_gated_lint(lint_flag_val, DUMMY_SP); let ids = match store.find_lints(&lint_name) { Ok(ids) => ids, Err(_) => continue, // errors handled in check_lint_name_cmdline above }; for id in ids { + self.check_gated_lint(id, DUMMY_SP); let src = LintSource::CommandLine(lint_flag_val); specs.insert(id, (level, src)); } @@ -213,9 +213,9 @@ impl<'s> LintLevelsBuilder<'s> { let name = meta_item.path.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { - self.check_gated_lint(name, attr.span); let src = LintSource::Node(name, li.span(), reason); for id in ids { + self.check_gated_lint(*id, attr.span); specs.insert(*id, (level, src)); } } @@ -386,8 +386,8 @@ impl<'s> LintLevelsBuilder<'s> { BuilderPush { prev, changed: prev != self.cur } } - fn check_gated_lint(&self, name: Symbol, span: Span) { - if name.as_str() == builtin::UNSAFE_OP_IN_UNSAFE_FN.name + fn check_gated_lint(&self, id: LintId, span: Span) { + if id == LintId::of(builtin::UNSAFE_OP_IN_UNSAFE_FN) && !self.sess.features_untracked().unsafe_block_in_unsafe_fn { feature_err( From 5548e692260c7d468294e5eccbeb63c3a829ee94 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 26 May 2020 10:33:40 +0200 Subject: [PATCH 359/695] Add working example for E0617 explanation --- src/librustc_error_codes/error_codes/E0617.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc_error_codes/error_codes/E0617.md b/src/librustc_error_codes/error_codes/E0617.md index f4357ff755e29..61b56766c26e2 100644 --- a/src/librustc_error_codes/error_codes/E0617.md +++ b/src/librustc_error_codes/error_codes/E0617.md @@ -17,3 +17,14 @@ Certain Rust types must be cast before passing them to a variadic function, because of arcane ABI rules dictated by the C standard. To fix the error, cast the value to the type specified by the error message (which you may need to import from `std::os::raw`). + +In this case, `c_double` has the same size as `f64` so we can use it directly: + +```no_run +# extern { +# fn printf(c: *const i8, ...); +# } +unsafe { + printf(::std::ptr::null(), 0f64); // ok! +} +``` From 5ba5b653673faff60f15ad875cd22da6d0afc2bb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 27 May 2020 11:46:23 +0200 Subject: [PATCH 360/695] Sort fields, variants and other unsorted elements in the sidebar --- src/librustdoc/html/render.rs | 63 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 646c663ad9ccd..aa3777624d29c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4064,9 +4064,9 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { .filter(|i| i.inner_impl().trait_.is_none()) .flat_map(move |i| get_methods(i.inner_impl(), false, used_links_bor, false)) .collect::>(); - // We want links' order to be reproducible so we don't use unstable sort. - ret.sort(); if !ret.is_empty() { + // We want links' order to be reproducible so we don't use unstable sort. + ret.sort(); out.push_str(&format!( "Methods\
{}
", @@ -4237,7 +4237,7 @@ fn is_negative_impl(i: &clean::Impl) -> bool { fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { let mut sidebar = String::new(); - let types = t + let mut types = t .items .iter() .filter_map(|m| match m.name { @@ -4246,8 +4246,8 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { } _ => None, }) - .collect::(); - let consts = t + .collect::>(); + let mut consts = t .items .iter() .filter_map(|m| match m.name { @@ -4256,7 +4256,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { } _ => None, }) - .collect::(); + .collect::>(); let mut required = t .items .iter() @@ -4279,24 +4279,26 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { .collect::>(); if !types.is_empty() { + types.sort(); sidebar.push_str(&format!( "\ - Associated Types
{}
", - types + Associated Types
{}
", + types.join("") )); } if !consts.is_empty() { + consts.sort(); sidebar.push_str(&format!( "\ - Associated Constants
{}
", - consts + Associated Constants
{}
", + consts.join("") )); } if !required.is_empty() { required.sort(); sidebar.push_str(&format!( "\ - Required Methods
{}
", + Required Methods
{}
", required.join("") )); } @@ -4304,7 +4306,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { provided.sort(); sidebar.push_str(&format!( "\ - Provided Methods
{}
", + Provided Methods
{}
", provided.join("") )); } @@ -4322,8 +4324,8 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { res.sort(); sidebar.push_str(&format!( "\ - Implementations on Foreign Types
{}
", + Implementations on Foreign Types
{}
", res.into_iter() .map(|(name, id)| format!("{}", id, Escape(&name))) .collect::>() @@ -4336,7 +4338,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { if t.auto { sidebar.push_str( "Auto Implementors", + href=\"#synthetic-implementors\">Auto Implementors", ); } @@ -4362,18 +4364,18 @@ fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item) { } fn get_struct_fields_name(fields: &[clean::Item]) -> String { - fields + let mut fields = fields .iter() .filter(|f| if let clean::StructFieldItem(..) = f.inner { true } else { false }) .filter_map(|f| match f.name { - Some(ref name) => Some(format!( - "\ - {name}", - name = name - )), + Some(ref name) => { + Some(format!("{name}", name = name)) + } _ => None, }) - .collect() + .collect::>(); + fields.sort(); + fields.join("") } fn sidebar_union(buf: &mut Buffer, it: &clean::Item, u: &clean::Union) { @@ -4383,7 +4385,7 @@ fn sidebar_union(buf: &mut Buffer, it: &clean::Item, u: &clean::Union) { if !fields.is_empty() { sidebar.push_str(&format!( "Fields\ -
{}
", +
{}
", fields )); } @@ -4398,23 +4400,20 @@ fn sidebar_union(buf: &mut Buffer, it: &clean::Item, u: &clean::Union) { fn sidebar_enum(buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) { let mut sidebar = String::new(); - let variants = e + let mut variants = e .variants .iter() .filter_map(|v| match v.name { - Some(ref name) => Some(format!( - "{name}\ - ", - name = name - )), + Some(ref name) => Some(format!("{name}", name = name)), _ => None, }) - .collect::(); + .collect::>(); if !variants.is_empty() { + variants.sort_unstable(); sidebar.push_str(&format!( "Variants\ -
{}
", - variants +
{}
", + variants.join(""), )); } From 5369f4aa57fc72c6f58368bb0f4977975ec2f1e6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 27 May 2020 21:34:17 +0300 Subject: [PATCH 361/695] rustc_session: Cleanup session creation --- src/librustc_interface/interface.rs | 9 ++--- src/librustc_interface/tests.rs | 12 +++++-- src/librustc_interface/util.rs | 8 ++--- src/librustc_session/parse.rs | 4 +++ src/librustc_session/session.rs | 55 ++++++++--------------------- src/librustdoc/test.rs | 2 +- 6 files changed, 35 insertions(+), 55 deletions(-) diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index 55f825e150e5e..f127a239eea2c 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -18,7 +18,7 @@ use rustc_session::lint; use rustc_session::parse::{CrateConfig, ParseSess}; use rustc_session::{DiagnosticOutput, Session}; use rustc_span::edition; -use rustc_span::source_map::{FileLoader, FileName, SourceMap}; +use rustc_span::source_map::{FileLoader, FileName}; use std::path::PathBuf; use std::result; use std::sync::{Arc, Mutex}; @@ -31,7 +31,6 @@ pub type Result = result::Result; pub struct Compiler { pub(crate) sess: Lrc, codegen_backend: Lrc>, - source_map: Lrc, pub(crate) input: Input, pub(crate) input_path: Option, pub(crate) output_dir: Option, @@ -49,9 +48,6 @@ impl Compiler { pub fn codegen_backend(&self) -> &Lrc> { &self.codegen_backend } - pub fn source_map(&self) -> &Lrc { - &self.source_map - } pub fn input(&self) -> &Input { &self.input } @@ -168,7 +164,7 @@ pub fn run_compiler_in_existing_thread_pool( f: impl FnOnce(&Compiler) -> R, ) -> R { let registry = &config.registry; - let (sess, codegen_backend, source_map) = util::create_session( + let (sess, codegen_backend) = util::create_session( config.opts, config.crate_cfg, config.diagnostic_output, @@ -181,7 +177,6 @@ pub fn run_compiler_in_existing_thread_pool( let compiler = Compiler { sess, codegen_backend, - source_map, input: config.input, input_path: config.input_path, output_dir: config.output_dir, diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index d573e11fc4b24..9390bbb34d03a 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -7,11 +7,10 @@ use rustc_session::config::{build_configuration, build_session_options, to_crate use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes}; use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; use rustc_session::config::{Externs, OutputType, OutputTypes, Sanitizer, SymbolManglingVersion}; -use rustc_session::getopts; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::NativeLibKind; -use rustc_session::{build_session, Session}; +use rustc_session::{build_session, getopts, DiagnosticOutput, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_span::SourceFileHashAlgorithm; @@ -32,7 +31,14 @@ fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { let registry = registry::Registry::new(&[]); let (sessopts, cfg) = build_session_options_and_crate_config(matches); - let sess = build_session(sessopts, None, registry); + let sess = build_session( + sessopts, + None, + registry, + DiagnosticOutput::Default, + Default::default(), + None, + ); (sess, cfg) } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 7eaaff05fb5f0..924908e572487 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -23,7 +23,7 @@ use rustc_session::parse::CrateConfig; use rustc_session::CrateDisambiguator; use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session}; use rustc_span::edition::Edition; -use rustc_span::source_map::{FileLoader, SourceMap}; +use rustc_span::source_map::FileLoader; use rustc_span::symbol::{sym, Symbol}; use smallvec::SmallVec; use std::env; @@ -65,8 +65,8 @@ pub fn create_session( input_path: Option, lint_caps: FxHashMap, descriptions: Registry, -) -> (Lrc, Lrc>, Lrc) { - let (mut sess, source_map) = session::build_session_with_source_map( +) -> (Lrc, Lrc>) { + let mut sess = session::build_session( sopts, input_path, descriptions, @@ -81,7 +81,7 @@ pub fn create_session( add_configuration(&mut cfg, &mut sess, &*codegen_backend); sess.parse_sess.config = cfg; - (Lrc::new(sess), Lrc::new(codegen_backend), source_map) + (Lrc::new(sess), Lrc::new(codegen_backend)) } const STACK_SIZE: usize = 8 * 1024 * 1024; diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs index 746e3536ce908..233761dbed7de 100644 --- a/src/librustc_session/parse.rs +++ b/src/librustc_session/parse.rs @@ -174,6 +174,10 @@ impl ParseSess { &self.source_map } + pub fn clone_source_map(&self) -> Lrc { + self.source_map.clone() + } + pub fn buffer_lint( &self, lint: &'static Lint, diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index f2f02cb649463..ba9741b1890f6 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -21,7 +21,7 @@ use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_span::edition::Edition; -use rustc_span::source_map::{self, FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; +use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; use rustc_span::{SourceFileHashAlgorithm, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; @@ -481,7 +481,7 @@ impl Session { } #[inline] - pub fn source_map(&self) -> &source_map::SourceMap { + pub fn source_map(&self) -> &SourceMap { self.parse_sess.source_map() } pub fn verbose(&self) -> bool { @@ -984,26 +984,10 @@ impl Session { } } -pub fn build_session( - sopts: config::Options, - local_crate_source_file: Option, - registry: rustc_errors::registry::Registry, -) -> Session { - build_session_with_source_map( - sopts, - local_crate_source_file, - registry, - DiagnosticOutput::Default, - Default::default(), - None, - ) - .0 -} - fn default_emitter( sopts: &config::Options, registry: rustc_errors::registry::Registry, - source_map: &Lrc, + source_map: Lrc, emitter_dest: Option>, ) -> Box { let macro_backtrace = sopts.debugging_opts.macro_backtrace; @@ -1012,17 +996,14 @@ fn default_emitter( let (short, color_config) = kind.unzip(); if let HumanReadableErrorType::AnnotateSnippet(_) = kind { - let emitter = AnnotateSnippetEmitterWriter::new( - Some(source_map.clone()), - short, - macro_backtrace, - ); + let emitter = + AnnotateSnippetEmitterWriter::new(Some(source_map), short, macro_backtrace); Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) } else { let emitter = match dst { None => EmitterWriter::stderr( color_config, - Some(source_map.clone()), + Some(source_map), short, sopts.debugging_opts.teach, sopts.debugging_opts.terminal_width, @@ -1030,7 +1011,7 @@ fn default_emitter( ), Some(dst) => EmitterWriter::new( dst, - Some(source_map.clone()), + Some(source_map), short, false, // no teach messages when writing to a buffer false, // no colors when writing to a buffer @@ -1042,20 +1023,14 @@ fn default_emitter( } } (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new( - JsonEmitter::stderr( - Some(registry), - source_map.clone(), - pretty, - json_rendered, - macro_backtrace, - ) - .ui_testing(sopts.debugging_opts.ui_testing), + JsonEmitter::stderr(Some(registry), source_map, pretty, json_rendered, macro_backtrace) + .ui_testing(sopts.debugging_opts.ui_testing), ), (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new( JsonEmitter::new( dst, Some(registry), - source_map.clone(), + source_map, pretty, json_rendered, macro_backtrace, @@ -1070,14 +1045,14 @@ pub enum DiagnosticOutput { Raw(Box), } -pub fn build_session_with_source_map( +pub fn build_session( sopts: config::Options, local_crate_source_file: Option, registry: rustc_errors::registry::Registry, diagnostics_output: DiagnosticOutput, driver_lint_caps: FxHashMap, file_loader: Option>, -) -> (Session, Lrc) { +) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed // later via the source code. @@ -1115,7 +1090,7 @@ pub fn build_session_with_source_map( sopts.file_path_mapping(), hash_kind, )); - let emitter = default_emitter(&sopts, registry, &source_map, write_dest); + let emitter = default_emitter(&sopts, registry, source_map.clone(), write_dest); let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags( emitter, @@ -1143,7 +1118,7 @@ pub fn build_session_with_source_map( None }; - let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map.clone()); + let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map); let sysroot = match &sopts.maybe_sysroot { Some(sysroot) => sysroot.clone(), None => filesearch::get_or_default_sysroot(), @@ -1266,7 +1241,7 @@ pub fn build_session_with_source_map( validate_commandline_args_with_session_available(&sess); - (sess, source_map) + sess } // If it is useful to have a Session available already for validating a diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 284e6d421ee2f..85ba4cbdc7e1b 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -114,7 +114,7 @@ pub fn run(options: Options) -> Result<(), String> { options, false, opts, - Some(compiler.source_map().clone()), + Some(compiler.session().parse_sess.clone_source_map()), None, enable_per_target_ignores, ); From 1ab0db1272671a83ef3e27cdb88780f9dd6b2345 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 27 May 2020 21:38:38 +0200 Subject: [PATCH 362/695] Fix incorrect comment in generator test --- src/test/ui/generator/resume-arg-size.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/generator/resume-arg-size.rs b/src/test/ui/generator/resume-arg-size.rs index 4f08ac0702bdb..b93dc54f7a97d 100644 --- a/src/test/ui/generator/resume-arg-size.rs +++ b/src/test/ui/generator/resume-arg-size.rs @@ -22,7 +22,7 @@ fn main() { }; // Neither of these generators have the resume arg live across the `yield`, so they should be - // 4 Bytes in size (only storing the discriminant) + // 1 Byte in size (only storing the discriminant) assert_eq!(size_of_val(&gen_copy), 1); assert_eq!(size_of_val(&gen_move), 1); } From b1063b83da7159c0dc8616fec26daeaa11b5f4d7 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 27 May 2020 17:25:47 -0400 Subject: [PATCH 363/695] Clippy should always build This just unwraps clippy's build step instead of skipping tests if clippy didn't build. This matches e.g. cargo's behavior and seems more correct, as we always expect clippy to successfully build. --- src/bootstrap/test.rs | 60 +++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index ed50f950fb697..f1305e2540b4c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -516,45 +516,37 @@ impl Step for Clippy { let host = self.host; let compiler = builder.compiler(stage, host); - let clippy = builder.ensure(tool::Clippy { + let clippy = builder + .ensure(tool::Clippy { compiler, target: self.host, extra_features: Vec::new() }) + .expect("in-tree tool"); + let mut cargo = tool::prepare_tool_cargo( + builder, compiler, - target: self.host, - extra_features: Vec::new(), - }); - if let Some(clippy) = clippy { - let mut cargo = tool::prepare_tool_cargo( - builder, - compiler, - Mode::ToolRustc, - host, - "test", - "src/tools/clippy", - SourceType::InTree, - &[], - ); + Mode::ToolRustc, + host, + "test", + "src/tools/clippy", + SourceType::InTree, + &[], + ); - // clippy tests need to know about the stage sysroot - cargo.env("SYSROOT", builder.sysroot(compiler)); - cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); - cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); - let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir()); - let target_libs = builder - .stage_out(compiler, Mode::ToolRustc) - .join(&self.host) - .join(builder.cargo_dir()); - cargo.env("HOST_LIBS", host_libs); - cargo.env("TARGET_LIBS", target_libs); - // clippy tests need to find the driver - cargo.env("CLIPPY_DRIVER_PATH", clippy); + // clippy tests need to know about the stage sysroot + cargo.env("SYSROOT", builder.sysroot(compiler)); + cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); + cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); + let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir()); + let target_libs = + builder.stage_out(compiler, Mode::ToolRustc).join(&self.host).join(builder.cargo_dir()); + cargo.env("HOST_LIBS", host_libs); + cargo.env("TARGET_LIBS", target_libs); + // clippy tests need to find the driver + cargo.env("CLIPPY_DRIVER_PATH", clippy); - cargo.arg("--").args(builder.config.cmd.test_args()); + cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + builder.add_rustc_lib_path(compiler, &mut cargo); - try_run(builder, &mut cargo.into()); - } else { - eprintln!("failed to test clippy: could not build"); - } + try_run(builder, &mut cargo.into()); } } From db684beb4e40aae70a38e22e4aa91251349bf49b Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 27 May 2020 19:32:00 +0200 Subject: [PATCH 364/695] Whitelist `unsafe_op_in_unsafe_fn` in rustdoc --- src/librustdoc/core.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index bf59b3f25734d..331ce1453e139 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -226,6 +226,11 @@ where { let warnings_lint_name = lint::builtin::WARNINGS.name; + // Whitelist feature-gated lints to avoid feature errors when trying to + // allow all lints. + // FIXME(LeSeulArtichaut): handle feature-gated lints properly. + let unsafe_op_in_unsafe_fn_name = rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN.name; + whitelisted_lints.push(warnings_lint_name.to_owned()); whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); @@ -236,7 +241,13 @@ where }; let lint_opts = lints() - .filter_map(|lint| if lint.name == warnings_lint_name { None } else { filter_call(lint) }) + .filter_map(|lint| { + if lint.name == warnings_lint_name || lint.name == unsafe_op_in_unsafe_fn_name { + None + } else { + filter_call(lint) + } + }) .chain(lint_opts.into_iter()) .collect::>(); From 64a05f56c33d4754808ef85e634f72a9053c56fd Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Thu, 28 May 2020 00:36:15 +0200 Subject: [PATCH 365/695] len_zero: skip ranges if feature `range_is_empty` is not enabled --- clippy_lints/src/len_zero.rs | 17 ++++++++++++++++- tests/ui/len_zero.fixed | 8 ++++++++ tests/ui/len_zero.rs | 8 ++++++++ tests/ui/len_zero_ranges.fixed | 14 ++++++++++++++ tests/ui/len_zero_ranges.rs | 14 ++++++++++++++ tests/ui/len_zero_ranges.stderr | 10 ++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 tests/ui/len_zero_ranges.fixed create mode 100644 tests/ui/len_zero_ranges.rs create mode 100644 tests/ui/len_zero_ranges.stderr diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 2ec0b5a8d6fb4..f5bfede75a761 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,4 +1,4 @@ -use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{get_item_name, higher, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -259,6 +259,17 @@ fn check_len( /// Checks if this type has an `is_empty` method. fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + /// Special case ranges until `range_is_empty` is stabilized. See issue 3807. + fn should_skip_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { + higher::range(cx, expr).map_or(false, |_| { + !cx.tcx + .features() + .declared_lib_features + .iter() + .any(|(name, _)| name.as_str() == "range_is_empty") + }) + } + /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssocItem) -> bool { if let ty::AssocKind::Fn = item.kind { @@ -284,6 +295,10 @@ fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { }) } + if should_skip_range(cx, expr) { + return false; + } + let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr)); match ty.kind { ty::Dynamic(ref tt, ..) => { diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index 624e5ef8fcf13..a29b832eb6019 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -141,3 +141,11 @@ fn main() { fn test_slice(b: &[u8]) { if !b.is_empty() {} } + +mod issue_3807 { + // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`. + // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965 + fn no_suggestion() { + let _ = (0..42).len() == 0; + } +} diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 7fba971cfd887..8fd0093f4fdbb 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -141,3 +141,11 @@ fn main() { fn test_slice(b: &[u8]) { if b.len() != 0 {} } + +mod issue_3807 { + // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`. + // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965 + fn no_suggestion() { + let _ = (0..42).len() == 0; + } +} diff --git a/tests/ui/len_zero_ranges.fixed b/tests/ui/len_zero_ranges.fixed new file mode 100644 index 0000000000000..7da26f8ff4d47 --- /dev/null +++ b/tests/ui/len_zero_ranges.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +#![feature(range_is_empty)] +#![warn(clippy::len_zero)] +#![allow(unused)] + +mod issue_3807 { + // With the feature enabled, `is_empty` should be suggested + fn suggestion_is_fine() { + let _ = (0..42).is_empty(); + } +} + +fn main() {} diff --git a/tests/ui/len_zero_ranges.rs b/tests/ui/len_zero_ranges.rs new file mode 100644 index 0000000000000..be7b4244bc06c --- /dev/null +++ b/tests/ui/len_zero_ranges.rs @@ -0,0 +1,14 @@ +// run-rustfix + +#![feature(range_is_empty)] +#![warn(clippy::len_zero)] +#![allow(unused)] + +mod issue_3807 { + // With the feature enabled, `is_empty` should be suggested + fn suggestion_is_fine() { + let _ = (0..42).len() == 0; + } +} + +fn main() {} diff --git a/tests/ui/len_zero_ranges.stderr b/tests/ui/len_zero_ranges.stderr new file mode 100644 index 0000000000000..6e5fa41fb08a5 --- /dev/null +++ b/tests/ui/len_zero_ranges.stderr @@ -0,0 +1,10 @@ +error: length comparison to zero + --> $DIR/len_zero_ranges.rs:10:17 + | +LL | let _ = (0..42).len() == 0; + | ^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0..42).is_empty()` + | + = note: `-D clippy::len-zero` implied by `-D warnings` + +error: aborting due to previous error + From 3fea832fd7cbff73cf8d5d409ea9aeee0577b0ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 19 Dec 2019 19:44:06 -0800 Subject: [PATCH 366/695] Fix spacing of expected/found notes without a label --- src/librustc_errors/diagnostic.rs | 15 ++++++++++++--- .../project-fn-ret-invariant.transmute.stderr | 8 ++++---- .../dyn-trait.stderr | 8 ++++---- src/test/ui/issues/issue-16683.stderr | 4 ++-- src/test/ui/issues/issue-17758.stderr | 4 ++-- src/test/ui/issues/issue-20831-debruijn.stderr | 4 ++-- src/test/ui/issues/issue-52213.stderr | 4 ++-- src/test/ui/issues/issue-55796.stderr | 8 ++++---- src/test/ui/nll/issue-55394.stderr | 4 ++-- .../ui/nll/normalization-bounds-error.stderr | 4 ++-- src/test/ui/nll/type-alias-free-regions.stderr | 16 ++++++++-------- .../constant-in-expr-inherent-1.stderr | 4 ++-- .../constant-in-expr-trait-item-3.stderr | 4 ++-- .../object-lifetime-default-elision.stderr | 8 ++++---- .../region-object-lifetime-in-coercion.stderr | 8 ++++---- ...soc-type-region-bound-in-trait-not-met.stderr | 8 ++++---- ...soc-type-static-bound-in-trait-not-met.stderr | 4 ++-- .../regions-close-object-into-object-2.stderr | 4 ++-- .../regions-close-object-into-object-4.stderr | 4 ++-- ...ons-close-over-type-parameter-multiple.stderr | 4 ++-- .../ui/regions/regions-creating-enums4.stderr | 8 ++++---- src/test/ui/regions/regions-nested-fns.stderr | 4 ++-- ...regions-normalize-in-where-clause-list.stderr | 4 ++-- .../ui/regions/regions-ret-borrowed-1.stderr | 4 ++-- src/test/ui/regions/regions-ret-borrowed.stderr | 4 ++-- .../regions-trait-object-subtyping.stderr | 4 ++-- src/test/ui/reject-specialized-drops-8142.stderr | 4 ++-- ...pertrait-has-wrong-lifetime-parameters.stderr | 4 ++-- .../dyn-trait-underscore.stderr | 4 ++-- 29 files changed, 88 insertions(+), 79 deletions(-) diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 1cc5daafed14e..cff83c3d5cda2 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -193,9 +193,18 @@ impl Diagnostic { expected_extra: &dyn fmt::Display, found_extra: &dyn fmt::Display, ) -> &mut Self { - let expected_label = format!("expected {}", expected_label); - - let found_label = format!("found {}", found_label); + let expected_label = expected_label.to_string(); + let expected_label = if expected_label.is_empty() { + "expected".to_string() + } else { + format!("expected {}", expected_label) + }; + let found_label = found_label.to_string(); + let found_label = if found_label.is_empty() { + "found".to_string() + } else { + format!("found {}", found_label) + }; let (found_padding, expected_padding) = if expected_label.len() > found_label.len() { (expected_label.len() - found_label.len(), 0) } else { diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 3e39c8a792446..137cb83ccd327 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -14,16 +14,16 @@ note: ...so that the expression is assignable | LL | bar(foo, x) | ^ - = note: expected `Type<'_>` - found `Type<'a>` + = note: expected `Type<'_>` + found `Type<'a>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the expression is assignable --> $DIR/project-fn-ret-invariant.rs:48:4 | LL | bar(foo, x) | ^^^^^^^^^^^ - = note: expected `Type<'static>` - found `Type<'_>` + = note: expected `Type<'static>` + found `Type<'_>` error: aborting due to previous error diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 3300293bb36ca..268008c211129 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -14,16 +14,16 @@ note: ...so that the expression is assignable | LL | static_val(x); | ^ - = note: expected `std::boxed::Box` - found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>` + = note: expected `std::boxed::Box` + found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the types are compatible --> $DIR/dyn-trait.rs:20:5 | LL | static_val(x); | ^^^^^^^^^^ - = note: expected `StaticTrait` - found `StaticTrait` + = note: expected `StaticTrait` + found `StaticTrait` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index 99700f2084e4a..4f65833075814 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -26,8 +26,8 @@ note: ...so that the types are compatible | LL | self.a(); | ^ - = note: expected `&'a Self` - found `&Self` + = note: expected `&'a Self` + found `&Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index adfc3f5085826..31788cfa61c4c 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -27,8 +27,8 @@ note: ...so that the types are compatible | LL | self.foo(); | ^^^ - = note: expected `&'a Self` - found `&Self` + = note: expected `&'a Self` + found `&Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr index a785a956ca9f5..160a4213a4043 100644 --- a/src/test/ui/issues/issue-20831-debruijn.stderr +++ b/src/test/ui/issues/issue-20831-debruijn.stderr @@ -117,8 +117,8 @@ note: ...so that the types are compatible | LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `Publisher<'_>` - found `Publisher<'_>` + = note: expected `Publisher<'_>` + found `Publisher<'_>` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-52213.stderr b/src/test/ui/issues/issue-52213.stderr index a8960f7756367..7463af9332a76 100644 --- a/src/test/ui/issues/issue-52213.stderr +++ b/src/test/ui/issues/issue-52213.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | match (&t,) { | ^^^^^ - = note: expected `(&&(T,),)` - found `(&&'a (T,),)` + = note: expected `(&&(T,),)` + found `(&&'a (T,),)` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27... --> $DIR/issue-52213.rs:1:27 | diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr index b8cafdc5c14b5..6bfb7af54446d 100644 --- a/src/test/ui/issues/issue-55796.stderr +++ b/src/test/ui/issues/issue-55796.stderr @@ -20,8 +20,8 @@ note: ...so that the expression is assignable | LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` - found `std::boxed::Box>::Node>>` + = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` + found `std::boxed::Box>::Node>>` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/issue-55796.rs:21:9 @@ -45,8 +45,8 @@ note: ...so that the expression is assignable | LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` - found `std::boxed::Box>::Node>>` + = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` + found `std::boxed::Box>::Node>>` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/issue-55394.stderr b/src/test/ui/nll/issue-55394.stderr index 69a6ab004fd91..ba8d91b8455bf 100644 --- a/src/test/ui/nll/issue-55394.stderr +++ b/src/test/ui/nll/issue-55394.stderr @@ -26,8 +26,8 @@ note: ...so that the expression is assignable | LL | Foo { bar } | ^^^^^^^^^^^ - = note: expected `Foo<'_>` - found `Foo<'_>` + = note: expected `Foo<'_>` + found `Foo<'_>` error: aborting due to previous error diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr index 58f206742f4f5..d003acd879a77 100644 --- a/src/test/ui/nll/normalization-bounds-error.stderr +++ b/src/test/ui/nll/normalization-bounds-error.stderr @@ -19,8 +19,8 @@ note: ...so that the types are compatible | LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `Visitor<'d>` - found `Visitor<'_>` + = note: expected `Visitor<'d>` + found `Visitor<'_>` error: aborting due to previous error diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index 5191deca281cc..3317aae83bb08 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -16,8 +16,8 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^ - = note: expected `std::boxed::Box>` - found `std::boxed::Box>` + = note: expected `std::boxed::Box>` + found `std::boxed::Box>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... --> $DIR/type-alias-free-regions.rs:15:6 | @@ -28,8 +28,8 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^^^^^^^^^^ - = note: expected `C<'a>` - found `C<'_>` + = note: expected `C<'a>` + found `C<'_>` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/type-alias-free-regions.rs:27:16 @@ -49,8 +49,8 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^ - = note: expected `std::boxed::Box<&isize>` - found `std::boxed::Box<&isize>` + = note: expected `std::boxed::Box<&isize>` + found `std::boxed::Box<&isize>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6... --> $DIR/type-alias-free-regions.rs:25:6 | @@ -61,8 +61,8 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `C<'a>` - found `C<'_>` + = note: expected `C<'a>` + found `C<'_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index 37be450fd0a79..8421dc1d0c130 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | >::C | ^^^^^^^^^^^^ - = note: expected `Foo<'_>` - found `Foo<'a>` + = note: expected `Foo<'_>` + found `Foo<'a>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that reference does not outlive borrowed content --> $DIR/constant-in-expr-inherent-1.rs:8:5 diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr index 4ee32847c5ec8..ba0a1748c5e9f 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | T::C | ^^^^ - = note: expected `Foo<'_>` - found `Foo<'a>` + = note: expected `Foo<'_>` + found `Foo<'a>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that reference does not outlive borrowed content --> $DIR/constant-in-expr-trait-item-3.rs:10:5 diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr index 1952ee8269d5b..79ded5fc875a2 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.stderr @@ -24,8 +24,8 @@ note: ...so that the expression is assignable | LL | ss | ^^ - = note: expected `&'b (dyn SomeTrait + 'b)` - found `&dyn SomeTrait` + = note: expected `&'b (dyn SomeTrait + 'b)` + found `&dyn SomeTrait` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/object-lifetime-default-elision.rs:71:5 @@ -53,8 +53,8 @@ note: ...so that the expression is assignable | LL | ss | ^^ - = note: expected `&'b (dyn SomeTrait + 'b)` - found `&dyn SomeTrait` + = note: expected `&'b (dyn SomeTrait + 'b)` + found `&dyn SomeTrait` error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index e889651647034..069b897603cb9 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -39,8 +39,8 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^ - = note: expected `&[u8]` - found `&'a [u8]` + = note: expected `&[u8]` + found `&'a [u8]` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9... --> $DIR/region-object-lifetime-in-coercion.rs:25:9 | @@ -51,8 +51,8 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn Foo + 'b)>` - found `std::boxed::Box` + = note: expected `std::boxed::Box<(dyn Foo + 'b)>` + found `std::boxed::Box` error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr index 865e967fba32e..c134b3b3ed554 100644 --- a/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr +++ b/src/test/ui/regions/regions-assoc-type-region-bound-in-trait-not-met.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | impl<'a> Foo<'static> for &'a i32 { | ^^^^^^^^^^^^ - = note: expected `Foo<'static>` - found `Foo<'static>` + = note: expected `Foo<'static>` + found `Foo<'static>` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the type `&i32` will meet its required lifetime bounds --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:14:10 @@ -39,8 +39,8 @@ note: ...so that the types are compatible | LL | impl<'a,'b> Foo<'b> for &'a i64 { | ^^^^^^^ - = note: expected `Foo<'b>` - found `Foo<'_>` + = note: expected `Foo<'b>` + found `Foo<'_>` note: but, the lifetime must be valid for the lifetime `'b` as defined on the impl at 19:9... --> $DIR/regions-assoc-type-region-bound-in-trait-not-met.rs:19:9 | diff --git a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr index 6a34871c07efd..ac8c55ccc8fd4 100644 --- a/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr +++ b/src/test/ui/regions/regions-assoc-type-static-bound-in-trait-not-met.stderr @@ -14,8 +14,8 @@ note: ...so that the types are compatible | LL | impl<'a> Foo for &'a i32 { | ^^^ - = note: expected `Foo` - found `Foo` + = note: expected `Foo` + found `Foo` = note: but, the lifetime must be valid for the static lifetime... note: ...so that the type `&i32` will meet its required lifetime bounds --> $DIR/regions-assoc-type-static-bound-in-trait-not-met.rs:9:10 diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 28873ab807f8d..147f7f3541816 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -20,8 +20,8 @@ note: ...so that the expression is assignable | LL | box B(&*v) as Box | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn X + 'static)>` - found `std::boxed::Box` + = note: expected `std::boxed::Box<(dyn X + 'static)>` + found `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 449a5b5fdd4d6..6e7d6152cd09a 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -20,8 +20,8 @@ note: ...so that the expression is assignable | LL | box B(&*v) as Box | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn X + 'static)>` - found `std::boxed::Box` + = note: expected `std::boxed::Box<(dyn X + 'static)>` + found `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr index b2a7afaf1b452..2070ce257b18d 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr @@ -24,8 +24,8 @@ note: ...so that the expression is assignable | LL | box v as Box | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>` - found `std::boxed::Box` + = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>` + found `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-creating-enums4.stderr b/src/test/ui/regions/regions-creating-enums4.stderr index 58f74e4ee142d..b24db1df18b0a 100644 --- a/src/test/ui/regions/regions-creating-enums4.stderr +++ b/src/test/ui/regions/regions-creating-enums4.stderr @@ -14,8 +14,8 @@ note: ...so that the expression is assignable | LL | Ast::Add(x, y) | ^ - = note: expected `&Ast<'_>` - found `&Ast<'a>` + = note: expected `&Ast<'_>` + found `&Ast<'a>` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:19... --> $DIR/regions-creating-enums4.rs:6:19 | @@ -26,8 +26,8 @@ note: ...so that the expression is assignable | LL | Ast::Add(x, y) | ^^^^^^^^^^^^^^ - = note: expected `Ast<'b>` - found `Ast<'_>` + = note: expected `Ast<'b>` + found `Ast<'_>` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr index 8fce1609d7830..9e405d83140d8 100644 --- a/src/test/ui/regions/regions-nested-fns.stderr +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -39,8 +39,8 @@ LL | | if false { return ay; } LL | | return z; LL | | })); | |_____^ - = note: expected `&isize` - found `&isize` + = note: expected `&isize` + found `&isize` error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/regions-nested-fns.rs:14:27 diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index c35516d2c0871..a274fd9d658a9 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -29,8 +29,8 @@ LL | | where <() as Project<'a, 'b>>::Item : Eq LL | | { LL | | } | |_^ - = note: expected `Project<'a, 'b>` - found `Project<'_, '_>` + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-normalize-in-where-clause-list.rs:22:1 diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr index 2895a0ccdeec8..2c4769d8e3751 100644 --- a/src/test/ui/regions/regions-ret-borrowed-1.stderr +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -14,8 +14,8 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&isize` - found `&isize` + = note: expected `&isize` + found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14... --> $DIR/regions-ret-borrowed-1.rs:9:14 | diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr index b74f10f5075eb..da560107cea99 100644 --- a/src/test/ui/regions/regions-ret-borrowed.stderr +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -14,8 +14,8 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&isize` - found `&isize` + = note: expected `&isize` + found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14... --> $DIR/regions-ret-borrowed.rs:12:14 | diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr index 58b79d212700c..7478b53bd3ccc 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -41,8 +41,8 @@ note: ...so that the expression is assignable | LL | x | ^ - = note: expected `&'b mut (dyn Dummy + 'b)` - found `&mut (dyn Dummy + 'b)` + = note: expected `&'b mut (dyn Dummy + 'b)` + found `&mut (dyn Dummy + 'b)` error[E0308]: mismatched types --> $DIR/regions-trait-object-subtyping.rs:22:5 diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr index c09418de51830..f819faa278995 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/reject-specialized-drops-8142.stderr @@ -118,8 +118,8 @@ note: ...so that the types are compatible | LL | impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `W<'l1, 'l2>` - found `W<'_, '_>` + = note: expected `W<'l1, 'l2>` + found `W<'_, '_>` error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the enum it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:61:14 diff --git a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr index 9fdcd4de495c0..46aa7db967ad4 100644 --- a/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr +++ b/src/test/ui/traits/trait-impl-of-supertrait-has-wrong-lifetime-parameters.stderr @@ -19,8 +19,8 @@ note: ...so that the types are compatible | LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> { | ^^^^^^^^^^ - = note: expected `T1<'a>` - found `T1<'_>` + = note: expected `T1<'a>` + found `T1<'_>` error: aborting due to previous error diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index e6029e0d4623a..e3c9d50dfe5b3 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -23,8 +23,8 @@ note: ...so that the expression is assignable | LL | Box::new(items.iter()) | ^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator + 'static)>` - found `std::boxed::Box>` + = note: expected `std::boxed::Box<(dyn std::iter::Iterator + 'static)>` + found `std::boxed::Box>` error: aborting due to previous error From 5ba22205a48f3c4232a899effc47fa1925ed9900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 20 Dec 2019 11:56:03 -0800 Subject: [PATCH 367/695] Name `RegionKind::ReVar` lifetimes in diagnostics --- .../infer/error_reporting/mod.rs | 9 ++-- .../trait_impl_difference.rs | 51 ++++++++++++++++++- src/test/ui/coercion/coerce-mut.rs | 4 +- src/test/ui/coercion/coerce-mut.stderr | 4 +- .../reordered-type-param.stderr | 2 +- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 2 +- .../impl-generic-mismatch-ab.stderr | 2 +- src/test/ui/impl-trait/trait_type.stderr | 2 +- .../mismatched_trait_impl-2.stderr | 4 +- .../mismatched_trait_impl.stderr | 4 +- src/test/ui/issues/issue-13033.rs | 2 +- src/test/ui/issues/issue-13033.stderr | 2 +- src/test/ui/issues/issue-16683.stderr | 2 +- src/test/ui/issues/issue-17758.stderr | 2 +- src/test/ui/issues/issue-20225.stderr | 8 ++- src/test/ui/issues/issue-21332.stderr | 2 +- ...ime-mismatch-between-trait-and-impl.stderr | 4 +- src/test/ui/mismatched_types/E0053.stderr | 2 +- .../trait-impl-fn-incompatibility.stderr | 2 +- .../ui/nll/type-alias-free-regions.stderr | 4 +- ...ons-fn-subtyping-return-static-fail.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 2 +- .../regions-fn-subtyping-return-static.stderr | 2 +- src/test/ui/regions/regions-nested-fns.stderr | 2 +- .../ui/regions/regions-ret-borrowed-1.stderr | 2 +- .../ui/regions/regions-ret-borrowed.stderr | 2 +- src/test/ui/regions/regions-trait-1.stderr | 2 +- .../regions-trait-object-subtyping.stderr | 2 +- .../resolve-inconsistent-binding-mode.stderr | 4 +- src/test/ui/span/coerce-suggestions.stderr | 4 +- .../traits/trait-impl-method-mismatch.stderr | 2 +- src/test/ui/type/type-mismatch.stderr | 4 +- src/test/ui/unsafe/unsafe-trait-impl.rs | 2 +- src/test/ui/unsafe/unsafe-trait-impl.stderr | 2 +- src/test/ui/wrong-mul-method-signature.stderr | 2 +- 35 files changed, 105 insertions(+), 45 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index cc479aa17ce95..66e7c87f2c351 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -987,13 +987,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fn push_ty_ref<'tcx>( - r: &ty::Region<'tcx>, + region: &ty::Region<'tcx>, ty: Ty<'tcx>, mutbl: hir::Mutability, s: &mut DiagnosticStyledString, ) { - let mut r = r.to_string(); - if r == "'_" { + let mut r = region.to_string(); + if let ty::RegionKind::ReVar(var) = region { + // Show these named, not as `'_` or elide them in "expected/found" notes. + r = format!("'z{} ", var.index()); + } else if r == "'_" { r.clear(); } else { r.push(' '); diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 695f3e47fb5d7..2e54a4e28e98c 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -1,11 +1,15 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. +use crate::hir::def_id::DefId; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::ErrorReported; -use rustc_middle::ty::Ty; +use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty}; use rustc_span::Span; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -52,9 +56,52 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); - err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); err.span_label(sp, &format!("found {:?}", found)); err.span_label(impl_sp, &format!("expected {:?}", expected)); + + struct EarlyBoundRegionHighlighter(FxHashSet); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for EarlyBoundRegionHighlighter { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + debug!("LateBoundRegionNameCollector visit_region {:?}", r); + match *r { + ty::ReFree(free) => { + self.0.insert(free.scope); + } + + ty::ReEarlyBound(bound) => { + self.0.insert(bound.def_id); + } + _ => {} + } + r.super_visit_with(self) + } + } + + let mut visitor = EarlyBoundRegionHighlighter(FxHashSet::default()); + expected.visit_with(&mut visitor); + + let note = !visitor.0.is_empty(); + + if let Some((expected, found)) = self + .tcx() + .infer_ctxt() + .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found })) + { + err.note_expected_found(&"", expected, &"", found); + } else { + // This fallback shouldn't be necessary, but let's keep it in just in case. + err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); + } + if note { + err.note( + "the lifetime requirements from the `trait` could not be fulfilled by the \ + `impl`", + ); + err.help( + "consider adding a named lifetime to the `trait` that constrains the item's \ + `self` argument, its inputs and its output with it", + ); + } err.emit(); } } diff --git a/src/test/ui/coercion/coerce-mut.rs b/src/test/ui/coercion/coerce-mut.rs index 43f0b55856d3c..3ccfe1cede7ac 100644 --- a/src/test/ui/coercion/coerce-mut.rs +++ b/src/test/ui/coercion/coerce-mut.rs @@ -4,7 +4,7 @@ fn main() { let x = 0; f(&x); //~^ ERROR mismatched types - //~| expected mutable reference `&mut i32` - //~| found reference `&{integer}` + //~| expected mutable reference `&'z1 mut i32` + //~| found reference `&'z2 {integer}` //~| types differ in mutability } diff --git a/src/test/ui/coercion/coerce-mut.stderr b/src/test/ui/coercion/coerce-mut.stderr index 2601ca5e91e5b..f5b13f6c59099 100644 --- a/src/test/ui/coercion/coerce-mut.stderr +++ b/src/test/ui/coercion/coerce-mut.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f(&x); | ^^ types differ in mutability | - = note: expected mutable reference `&mut i32` - found reference `&{integer}` + = note: expected mutable reference `&'z1 mut i32` + found reference `&'z2 {integer}` error: aborting due to previous error diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr index f1f8a663f2120..9eed16fa994e3 100644 --- a/src/test/ui/compare-method/reordered-type-param.stderr +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -11,7 +11,7 @@ LL | fn b(&self, _x: G) -> G { panic!() } | expected type parameter | = note: expected fn pointer `fn(&E, F) -> F` - found fn pointer `fn(&E, G) -> G` + found fn pointer `fn(&'z0 E, G) -> G` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 328e98657effb..4d09fe74e16fc 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -7,7 +7,7 @@ LL | let _: for<'b> fn(&'b u32) = foo(); | expected due to this | = note: expected fn pointer `for<'b> fn(&'b u32)` - found fn pointer `fn(&u32)` + found fn pointer `fn(&'z0 u32)` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr index 638a0093fb21d..d5725efbac3c6 100644 --- a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr +++ b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr @@ -10,7 +10,7 @@ LL | fn foo(&self, a: &impl Debug, b: &B) { } | expected type parameter | = note: expected fn pointer `fn(&(), &B, &impl Debug)` - found fn pointer `fn(&(), &impl Debug, &B)` + found fn pointer `fn(&'z0 (), &impl Debug, &B)` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 748bc639a03c2..3cc9c1a7fb054 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -5,7 +5,7 @@ LL | fn fmt(&self, x: &str) -> () { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` - found fn pointer `fn(&MyType, &str)` + found fn pointer `fn(&'z0 MyType, &str)` error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2 --> $DIR/trait_type.rs:12:11 diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index c1c4ec9ed7b92..349f813b20d50 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -10,7 +10,9 @@ LL | fn deref(&self) -> &Self::Target; | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static) | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` - found `fn(&Struct) -> &dyn Trait` + found `fn(&'z0 Struct) -> &dyn Trait` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 15891c9e7a62d..72960a41f93df 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -8,7 +8,9 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` - found `fn(&i32, &u32, &u32) -> &u32` + found `fn(&'z0 i32, &'z1 u32, &'z2 u32) -> &'z2 u32` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it error[E0623]: lifetime mismatch --> $DIR/mismatched_trait_impl.rs:10:9 diff --git a/src/test/ui/issues/issue-13033.rs b/src/test/ui/issues/issue-13033.rs index 7631831a81a5b..3fa94fac23759 100644 --- a/src/test/ui/issues/issue-13033.rs +++ b/src/test/ui/issues/issue-13033.rs @@ -8,7 +8,7 @@ impl Foo for Baz { fn bar(&mut self, other: &dyn Foo) {} //~^ ERROR method `bar` has an incompatible type for trait //~| expected fn pointer `fn(&mut Baz, &mut dyn Foo)` - //~| found fn pointer `fn(&mut Baz, &dyn Foo)` + //~| found fn pointer `fn(&'z0 mut Baz, &dyn Foo)` } fn main() {} diff --git a/src/test/ui/issues/issue-13033.stderr b/src/test/ui/issues/issue-13033.stderr index a8473c8a52413..238f41782ba5a 100644 --- a/src/test/ui/issues/issue-13033.stderr +++ b/src/test/ui/issues/issue-13033.stderr @@ -8,7 +8,7 @@ LL | fn bar(&mut self, other: &dyn Foo) {} | ^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)` - found fn pointer `fn(&mut Baz, &dyn Foo)` + found fn pointer `fn(&'z0 mut Baz, &dyn Foo)` help: consider change the type to match the mutability in trait | LL | fn bar(&mut self, other: &mut dyn Foo) {} diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index 4f65833075814..fa782d043312d 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -27,7 +27,7 @@ note: ...so that the types are compatible LL | self.a(); | ^ = note: expected `&'a Self` - found `&Self` + found `&'z0 Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index 31788cfa61c4c..7c382b95ae9af 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -28,7 +28,7 @@ note: ...so that the types are compatible LL | self.foo(); | ^^^ = note: expected `&'a Self` - found `&Self` + found `&'z0 Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr index 3bcc50ded8425..351973d444b05 100644 --- a/src/test/ui/issues/issue-20225.stderr +++ b/src/test/ui/issues/issue-20225.stderr @@ -7,7 +7,9 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` | = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))` - found fn pointer `extern "rust-call" fn(&Foo, (T,))` + found fn pointer `extern "rust-call" fn(&'z0 Foo, (T,))` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_mut` has an incompatible type for trait --> $DIR/issue-20225.rs:11:3 @@ -18,7 +20,9 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` | = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))` - found fn pointer `extern "rust-call" fn(&mut Foo, (T,))` + found fn pointer `extern "rust-call" fn(&'z0 mut Foo, (T,))` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_once` has an incompatible type for trait --> $DIR/issue-20225.rs:18:3 diff --git a/src/test/ui/issues/issue-21332.stderr b/src/test/ui/issues/issue-21332.stderr index ace3e014647c9..cc95b31acb7a7 100644 --- a/src/test/ui/issues/issue-21332.stderr +++ b/src/test/ui/issues/issue-21332.stderr @@ -5,7 +5,7 @@ LL | fn next(&mut self) -> Result { Ok(7) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | = note: expected fn pointer `fn(&mut S) -> std::option::Option` - found fn pointer `fn(&mut S) -> std::result::Result` + found fn pointer `fn(&'z0 mut S) -> std::result::Result` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index d07f305954b6e..57d145dcc20a0 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -8,7 +8,9 @@ LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32 | = note: expected `fn(&i32, &'a i32) -> &'a i32` - found `fn(&i32, &i32) -> &i32` + found `fn(&'z0 i32, &'z0 i32) -> &'z0 i32` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr index fef83e6bbe2b6..4926068e583e7 100644 --- a/src/test/ui/mismatched_types/E0053.stderr +++ b/src/test/ui/mismatched_types/E0053.stderr @@ -20,7 +20,7 @@ LL | fn bar(&mut self) { } | ^^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&Bar)` - found fn pointer `fn(&mut Bar)` + found fn pointer `fn(&'z0 mut Bar)` help: consider change the type to match the mutability in trait | LL | fn bar(&self) { } diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index b20fddb05acf1..debb371db5104 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -20,7 +20,7 @@ LL | fn bar(&mut self, bar: &Bar) { } | ^^^^ types differ in mutability | = note: expected fn pointer `fn(&mut Bar, &mut Bar)` - found fn pointer `fn(&mut Bar, &Bar)` + found fn pointer `fn(&'z0 mut Bar, &'z1 Bar)` help: consider change the type to match the mutability in trait | LL | fn bar(&mut self, bar: &mut Bar) { } diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index 3317aae83bb08..d029cd23a8b24 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -16,7 +16,7 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^ - = note: expected `std::boxed::Box>` + = note: expected `std::boxed::Box>` found `std::boxed::Box>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... --> $DIR/type-alias-free-regions.rs:15:6 @@ -49,7 +49,7 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^ - = note: expected `std::boxed::Box<&isize>` + = note: expected `std::boxed::Box<&'z1 isize>` found `std::boxed::Box<&isize>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6... --> $DIR/type-alias-free-regions.rs:25:6 diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 27704b3e0a8c7..074f78027c3b8 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -5,7 +5,7 @@ LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` + found fn item `for<'a> fn(&'a S) -> &'z2 S {bar::<'_>}` error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 069b897603cb9..cbe8d01f97729 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -39,7 +39,7 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^ - = note: expected `&[u8]` + = note: expected `&'z1 [u8]` found `&'a [u8]` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9... --> $DIR/region-object-lifetime-in-coercion.rs:25:9 diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr index a8a7e97e6acf6..b26891a678980 100644 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr @@ -5,7 +5,7 @@ LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` + found fn item `for<'a> fn(&'a S) -> &'z2 S {bar::<'_>}` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr index 9e405d83140d8..40e9146d6894a 100644 --- a/src/test/ui/regions/regions-nested-fns.stderr +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -40,7 +40,7 @@ LL | | return z; LL | | })); | |_____^ = note: expected `&isize` - found `&isize` + found `&'z13 isize` error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/regions-nested-fns.rs:14:27 diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr index 2c4769d8e3751..b489290d9f71d 100644 --- a/src/test/ui/regions/regions-ret-borrowed-1.stderr +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -14,7 +14,7 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&isize` + = note: expected `&'z0 isize` found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14... --> $DIR/regions-ret-borrowed-1.rs:9:14 diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr index da560107cea99..6b2a041b95bc3 100644 --- a/src/test/ui/regions/regions-ret-borrowed.stderr +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -14,7 +14,7 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&isize` + = note: expected `&'z0 isize` found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14... --> $DIR/regions-ret-borrowed.rs:12:14 diff --git a/src/test/ui/regions/regions-trait-1.stderr b/src/test/ui/regions/regions-trait-1.stderr index 60ac7c09f0414..6b3c40658a73d 100644 --- a/src/test/ui/regions/regions-trait-1.stderr +++ b/src/test/ui/regions/regions-trait-1.stderr @@ -5,7 +5,7 @@ LL | fn get_ctxt(&self) -> &'a Ctxt { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&HasCtxt<'a>) -> &Ctxt` - found fn pointer `fn(&HasCtxt<'a>) -> &'a Ctxt` + found fn pointer `fn(&'z0 HasCtxt<'a>) -> &'a Ctxt` note: the lifetime `'a` as defined on the impl at 12:6... --> $DIR/regions-trait-1.rs:12:6 | diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr index 7478b53bd3ccc..271849fdef693 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -42,7 +42,7 @@ note: ...so that the expression is assignable LL | x | ^ = note: expected `&'b mut (dyn Dummy + 'b)` - found `&mut (dyn Dummy + 'b)` + found `&'z1 mut (dyn Dummy + 'b)` error[E0308]: mismatched types --> $DIR/regions-trait-object-subtyping.rs:22:5 diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr index c14dfa3601a8c..0d19ea1ff2507 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr @@ -54,8 +54,8 @@ LL | Opts::A(ref mut i) | Opts::B(ref i) => {} | | | first introduced with type `&mut isize` here | - = note: expected type `&mut isize` - found type `&isize` + = note: expected type `&'z0 mut isize` + found type `&'z1 isize` = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 6 previous errors diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index d1960a8aab300..8ea45e4191da7 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -22,8 +22,8 @@ error[E0308]: mismatched types LL | test(&y); | ^^ types differ in mutability | - = note: expected mutable reference `&mut std::string::String` - found reference `&std::string::String` + = note: expected mutable reference `&'z2 mut std::string::String` + found reference `&'z3 std::string::String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:14:11 diff --git a/src/test/ui/traits/trait-impl-method-mismatch.stderr b/src/test/ui/traits/trait-impl-method-mismatch.stderr index 52e4918624168..517da553dc0ee 100644 --- a/src/test/ui/traits/trait-impl-method-mismatch.stderr +++ b/src/test/ui/traits/trait-impl-method-mismatch.stderr @@ -8,7 +8,7 @@ LL | unsafe fn jumbo(&self, x: &usize) { *self + *x; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn | = note: expected fn pointer `fn(&usize, &usize) -> usize` - found fn pointer `unsafe fn(&usize, &usize)` + found fn pointer `unsafe fn(&'z0 usize, &'z1 usize)` error: aborting due to previous error diff --git a/src/test/ui/type/type-mismatch.stderr b/src/test/ui/type/type-mismatch.stderr index 24c71c63103d3..7beffa0e5e493 100644 --- a/src/test/ui/type/type-mismatch.stderr +++ b/src/test/ui/type/type-mismatch.stderr @@ -211,7 +211,7 @@ LL | want::<&Foo>(f); | expected `&Foo`, found struct `Foo` | help: consider borrowing here: `&f` | - = note: expected reference `&Foo` + = note: expected reference `&'z0 Foo` found struct `Foo` error[E0308]: mismatched types @@ -313,7 +313,7 @@ LL | want::<&Foo>(f); | expected `&Foo`, found struct `Foo` | help: consider borrowing here: `&f` | - = note: expected reference `&Foo` + = note: expected reference `&'z1 Foo` found struct `Foo` error[E0308]: mismatched types diff --git a/src/test/ui/unsafe/unsafe-trait-impl.rs b/src/test/ui/unsafe/unsafe-trait-impl.rs index 03a251be1a914..691c751a080f1 100644 --- a/src/test/ui/unsafe/unsafe-trait-impl.rs +++ b/src/test/ui/unsafe/unsafe-trait-impl.rs @@ -8,7 +8,7 @@ impl Foo for u32 { fn len(&self) -> u32 { *self } //~^ ERROR method `len` has an incompatible type for trait //~| expected fn pointer `unsafe fn(&u32) -> _` - //~| found fn pointer `fn(&u32) -> _` + //~| found fn pointer `fn(&'z0 u32) -> _` } fn main() { } diff --git a/src/test/ui/unsafe/unsafe-trait-impl.stderr b/src/test/ui/unsafe/unsafe-trait-impl.stderr index 1c3d057cbc9ce..f163790eb4511 100644 --- a/src/test/ui/unsafe/unsafe-trait-impl.stderr +++ b/src/test/ui/unsafe/unsafe-trait-impl.stderr @@ -8,7 +8,7 @@ LL | fn len(&self) -> u32 { *self } | ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found normal fn | = note: expected fn pointer `unsafe fn(&u32) -> _` - found fn pointer `fn(&u32) -> _` + found fn pointer `fn(&'z0 u32) -> _` error: aborting due to previous error diff --git a/src/test/ui/wrong-mul-method-signature.stderr b/src/test/ui/wrong-mul-method-signature.stderr index 4c367fb9e9caf..cb901cdeedf0c 100644 --- a/src/test/ui/wrong-mul-method-signature.stderr +++ b/src/test/ui/wrong-mul-method-signature.stderr @@ -5,7 +5,7 @@ LL | fn mul(self, s: &f64) -> Vec1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found `&f64` | = note: expected fn pointer `fn(Vec1, f64) -> Vec1` - found fn pointer `fn(Vec1, &f64) -> Vec1` + found fn pointer `fn(Vec1, &'z0 f64) -> Vec1` error[E0053]: method `mul` has an incompatible type for trait --> $DIR/wrong-mul-method-signature.rs:33:5 From eb0f4d51df3be5b149ec032d62e9431ba4faf038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 22 Dec 2019 13:53:01 -0800 Subject: [PATCH 368/695] Tweak output for mismatched impl item Detect type parameter that might require lifetime constraint. Do not name `ReVar`s in expected/found output. Reword text suggesting to check the lifetimes. --- .../infer/error_reporting/mod.rs | 5 +- .../trait_impl_difference.rs | 51 +++++++++++++++---- src/test/ui/coercion/coerce-mut.rs | 4 +- src/test/ui/coercion/coerce-mut.stderr | 4 +- .../reordered-type-param.stderr | 2 +- src/test/ui/hrtb/hrtb-exists-forall-fn.stderr | 2 +- .../impl-generic-mismatch-ab.stderr | 2 +- src/test/ui/impl-trait/trait_type.stderr | 2 +- .../mismatched_trait_impl-2.stderr | 4 +- .../mismatched_trait_impl.nll.stderr | 2 + .../mismatched_trait_impl.stderr | 4 +- src/test/ui/issues/issue-13033.rs | 2 +- src/test/ui/issues/issue-13033.stderr | 2 +- src/test/ui/issues/issue-16683.stderr | 2 +- src/test/ui/issues/issue-17758.stderr | 2 +- src/test/ui/issues/issue-20225.stderr | 4 +- src/test/ui/issues/issue-21332.stderr | 2 +- ...ime-mismatch-between-trait-and-impl.stderr | 4 +- src/test/ui/mismatched_types/E0053.stderr | 2 +- .../trait-impl-fn-incompatibility.stderr | 2 +- .../ui/nll/type-alias-free-regions.stderr | 4 +- ...ons-fn-subtyping-return-static-fail.stderr | 2 +- .../region-object-lifetime-in-coercion.stderr | 2 +- .../regions-fn-subtyping-return-static.stderr | 2 +- src/test/ui/regions/regions-nested-fns.stderr | 2 +- .../ui/regions/regions-ret-borrowed-1.stderr | 2 +- .../ui/regions/regions-ret-borrowed.stderr | 2 +- src/test/ui/regions/regions-trait-1.stderr | 2 +- .../regions-trait-object-subtyping.stderr | 2 +- .../resolve-inconsistent-binding-mode.stderr | 4 +- src/test/ui/span/coerce-suggestions.stderr | 4 +- .../traits/trait-impl-method-mismatch.stderr | 2 +- ...trait-param-without-lifetime-constraint.rs | 20 ++++++++ ...t-param-without-lifetime-constraint.stderr | 18 +++++++ src/test/ui/type/type-mismatch.stderr | 4 +- src/test/ui/unsafe/unsafe-trait-impl.rs | 2 +- src/test/ui/unsafe/unsafe-trait-impl.stderr | 2 +- src/test/ui/wrong-mul-method-signature.stderr | 2 +- 38 files changed, 126 insertions(+), 56 deletions(-) create mode 100644 src/test/ui/traits/trait-param-without-lifetime-constraint.rs create mode 100644 src/test/ui/traits/trait-param-without-lifetime-constraint.stderr diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 66e7c87f2c351..ae9019828170f 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -993,10 +993,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { s: &mut DiagnosticStyledString, ) { let mut r = region.to_string(); - if let ty::RegionKind::ReVar(var) = region { - // Show these named, not as `'_` or elide them in "expected/found" notes. - r = format!("'z{} ", var.index()); - } else if r == "'_" { + if r == "'_" { r.clear(); } else { r.push(' '); diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 2e54a4e28e98c..5aa55d253aa1e 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -1,5 +1,6 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. +use crate::hir; use crate::hir::def_id::DefId; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; @@ -40,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { var_origin.span(), sub_expected_found.expected, sub_expected_found.found, - self.tcx().def_span(*trait_item_def_id), + *trait_item_def_id, ); return Some(ErrorReported); } @@ -51,23 +52,56 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { None } - fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) { + fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) { + let tcx = self.tcx(); + let trait_sp = self.tcx().def_span(trait_def_id); let mut err = self .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); err.span_label(sp, &format!("found {:?}", found)); - err.span_label(impl_sp, &format!("expected {:?}", expected)); + err.span_label(trait_sp, &format!("expected {:?}", expected)); + let trait_fn_sig = tcx.fn_sig(trait_def_id); + + struct AssocTypeFinder(FxHashSet); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); + match ty.kind { + ty::Param(param) => { + self.0.insert(param); + } + _ => {} + } + ty.super_visit_with(self) + } + } + let mut visitor = AssocTypeFinder(FxHashSet::default()); + trait_fn_sig.output().visit_with(&mut visitor); + + if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { + let parent_id = tcx.hir().get_parent_item(id); + let trait_item = tcx.hir().expect_item(parent_id); + if let hir::ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { + for param_ty in visitor.0 { + if let Some(generic) = generics.get_named(param_ty.name) { + err.span_label(generic.span, &format!( + "in order for `impl` items to be able to implement the method, this \ + type parameter might need a lifetime restriction like `{}: 'a`", + param_ty.name, + )); + } + } + } + } struct EarlyBoundRegionHighlighter(FxHashSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for EarlyBoundRegionHighlighter { fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - debug!("LateBoundRegionNameCollector visit_region {:?}", r); match *r { ty::ReFree(free) => { self.0.insert(free.scope); } - ty::ReEarlyBound(bound) => { self.0.insert(bound.def_id); } @@ -94,12 +128,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if note { err.note( - "the lifetime requirements from the `trait` could not be fulfilled by the \ - `impl`", + "the lifetime requirements from the `trait` could not be fulfilled by the `impl`", ); err.help( - "consider adding a named lifetime to the `trait` that constrains the item's \ - `self` argument, its inputs and its output with it", + "verify the lifetime relationships in the `trait` and `impl` between the \ + `self` argument, the other inputs and its output", ); } err.emit(); diff --git a/src/test/ui/coercion/coerce-mut.rs b/src/test/ui/coercion/coerce-mut.rs index 3ccfe1cede7ac..43f0b55856d3c 100644 --- a/src/test/ui/coercion/coerce-mut.rs +++ b/src/test/ui/coercion/coerce-mut.rs @@ -4,7 +4,7 @@ fn main() { let x = 0; f(&x); //~^ ERROR mismatched types - //~| expected mutable reference `&'z1 mut i32` - //~| found reference `&'z2 {integer}` + //~| expected mutable reference `&mut i32` + //~| found reference `&{integer}` //~| types differ in mutability } diff --git a/src/test/ui/coercion/coerce-mut.stderr b/src/test/ui/coercion/coerce-mut.stderr index f5b13f6c59099..2601ca5e91e5b 100644 --- a/src/test/ui/coercion/coerce-mut.stderr +++ b/src/test/ui/coercion/coerce-mut.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f(&x); | ^^ types differ in mutability | - = note: expected mutable reference `&'z1 mut i32` - found reference `&'z2 {integer}` + = note: expected mutable reference `&mut i32` + found reference `&{integer}` error: aborting due to previous error diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr index 9eed16fa994e3..f1f8a663f2120 100644 --- a/src/test/ui/compare-method/reordered-type-param.stderr +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -11,7 +11,7 @@ LL | fn b(&self, _x: G) -> G { panic!() } | expected type parameter | = note: expected fn pointer `fn(&E, F) -> F` - found fn pointer `fn(&'z0 E, G) -> G` + found fn pointer `fn(&E, G) -> G` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr index 4d09fe74e16fc..328e98657effb 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr @@ -7,7 +7,7 @@ LL | let _: for<'b> fn(&'b u32) = foo(); | expected due to this | = note: expected fn pointer `for<'b> fn(&'b u32)` - found fn pointer `fn(&'z0 u32)` + found fn pointer `fn(&u32)` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr index d5725efbac3c6..638a0093fb21d 100644 --- a/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr +++ b/src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr @@ -10,7 +10,7 @@ LL | fn foo(&self, a: &impl Debug, b: &B) { } | expected type parameter | = note: expected fn pointer `fn(&(), &B, &impl Debug)` - found fn pointer `fn(&'z0 (), &impl Debug, &B)` + found fn pointer `fn(&(), &impl Debug, &B)` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 3cc9c1a7fb054..748bc639a03c2 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -5,7 +5,7 @@ LL | fn fmt(&self, x: &str) -> () { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` - found fn pointer `fn(&'z0 MyType, &str)` + found fn pointer `fn(&MyType, &str)` error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2 --> $DIR/trait_type.rs:12:11 diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index 349f813b20d50..d8a2fa14333ea 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -10,9 +10,9 @@ LL | fn deref(&self) -> &Self::Target; | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static) | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` - found `fn(&'z0 Struct) -> &dyn Trait` + found `fn(&Struct) -> &dyn Trait` = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` - = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index c245d78ae828f..88edf10a66f0c 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -9,6 +9,8 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 72960a41f93df..dcdc6d330c0e7 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -8,9 +8,9 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` - found `fn(&'z0 i32, &'z1 u32, &'z2 u32) -> &'z2 u32` + found `fn(&i32, &u32, &u32) -> &u32` = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` - = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error[E0623]: lifetime mismatch --> $DIR/mismatched_trait_impl.rs:10:9 diff --git a/src/test/ui/issues/issue-13033.rs b/src/test/ui/issues/issue-13033.rs index 3fa94fac23759..7631831a81a5b 100644 --- a/src/test/ui/issues/issue-13033.rs +++ b/src/test/ui/issues/issue-13033.rs @@ -8,7 +8,7 @@ impl Foo for Baz { fn bar(&mut self, other: &dyn Foo) {} //~^ ERROR method `bar` has an incompatible type for trait //~| expected fn pointer `fn(&mut Baz, &mut dyn Foo)` - //~| found fn pointer `fn(&'z0 mut Baz, &dyn Foo)` + //~| found fn pointer `fn(&mut Baz, &dyn Foo)` } fn main() {} diff --git a/src/test/ui/issues/issue-13033.stderr b/src/test/ui/issues/issue-13033.stderr index 238f41782ba5a..a8473c8a52413 100644 --- a/src/test/ui/issues/issue-13033.stderr +++ b/src/test/ui/issues/issue-13033.stderr @@ -8,7 +8,7 @@ LL | fn bar(&mut self, other: &dyn Foo) {} | ^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)` - found fn pointer `fn(&'z0 mut Baz, &dyn Foo)` + found fn pointer `fn(&mut Baz, &dyn Foo)` help: consider change the type to match the mutability in trait | LL | fn bar(&mut self, other: &mut dyn Foo) {} diff --git a/src/test/ui/issues/issue-16683.stderr b/src/test/ui/issues/issue-16683.stderr index fa782d043312d..4f65833075814 100644 --- a/src/test/ui/issues/issue-16683.stderr +++ b/src/test/ui/issues/issue-16683.stderr @@ -27,7 +27,7 @@ note: ...so that the types are compatible LL | self.a(); | ^ = note: expected `&'a Self` - found `&'z0 Self` + found `&Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.stderr b/src/test/ui/issues/issue-17758.stderr index 7c382b95ae9af..31788cfa61c4c 100644 --- a/src/test/ui/issues/issue-17758.stderr +++ b/src/test/ui/issues/issue-17758.stderr @@ -28,7 +28,7 @@ note: ...so that the types are compatible LL | self.foo(); | ^^^ = note: expected `&'a Self` - found `&'z0 Self` + found `&Self` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr index 351973d444b05..133dbc554c089 100644 --- a/src/test/ui/issues/issue-20225.stderr +++ b/src/test/ui/issues/issue-20225.stderr @@ -7,7 +7,7 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` | = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))` - found fn pointer `extern "rust-call" fn(&'z0 Foo, (T,))` + found fn pointer `extern "rust-call" fn(&Foo, (T,))` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters @@ -20,7 +20,7 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&T`, found type parameter `T` | = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))` - found fn pointer `extern "rust-call" fn(&'z0 mut Foo, (T,))` + found fn pointer `extern "rust-call" fn(&mut Foo, (T,))` = help: type parameters must be constrained to match other types = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/src/test/ui/issues/issue-21332.stderr b/src/test/ui/issues/issue-21332.stderr index cc95b31acb7a7..ace3e014647c9 100644 --- a/src/test/ui/issues/issue-21332.stderr +++ b/src/test/ui/issues/issue-21332.stderr @@ -5,7 +5,7 @@ LL | fn next(&mut self) -> Result { Ok(7) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | = note: expected fn pointer `fn(&mut S) -> std::option::Option` - found fn pointer `fn(&'z0 mut S) -> std::result::Result` + found fn pointer `fn(&mut S) -> std::result::Result` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index 57d145dcc20a0..fa2ea83deefb7 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -8,9 +8,9 @@ LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32 | = note: expected `fn(&i32, &'a i32) -> &'a i32` - found `fn(&'z0 i32, &'z0 i32) -> &'z0 i32` + found `fn(&i32, &i32) -> &i32` = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` - = help: consider adding a named lifetime to the `trait` that constrains the item's `self` argument, its inputs and its output with it + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr index 4926068e583e7..fef83e6bbe2b6 100644 --- a/src/test/ui/mismatched_types/E0053.stderr +++ b/src/test/ui/mismatched_types/E0053.stderr @@ -20,7 +20,7 @@ LL | fn bar(&mut self) { } | ^^^^^^^^^ types differ in mutability | = note: expected fn pointer `fn(&Bar)` - found fn pointer `fn(&'z0 mut Bar)` + found fn pointer `fn(&mut Bar)` help: consider change the type to match the mutability in trait | LL | fn bar(&self) { } diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index debb371db5104..b20fddb05acf1 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -20,7 +20,7 @@ LL | fn bar(&mut self, bar: &Bar) { } | ^^^^ types differ in mutability | = note: expected fn pointer `fn(&mut Bar, &mut Bar)` - found fn pointer `fn(&'z0 mut Bar, &'z1 Bar)` + found fn pointer `fn(&mut Bar, &Bar)` help: consider change the type to match the mutability in trait | LL | fn bar(&mut self, bar: &mut Bar) { } diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index d029cd23a8b24..3317aae83bb08 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -16,7 +16,7 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^ - = note: expected `std::boxed::Box>` + = note: expected `std::boxed::Box>` found `std::boxed::Box>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... --> $DIR/type-alias-free-regions.rs:15:6 @@ -49,7 +49,7 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^ - = note: expected `std::boxed::Box<&'z1 isize>` + = note: expected `std::boxed::Box<&isize>` found `std::boxed::Box<&isize>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 25:6... --> $DIR/type-alias-free-regions.rs:25:6 diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr index 074f78027c3b8..27704b3e0a8c7 100644 --- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr +++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr @@ -5,7 +5,7 @@ LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &'z2 S {bar::<'_>}` + found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` error[E0308]: mismatched types --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12 diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index cbe8d01f97729..069b897603cb9 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -39,7 +39,7 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^ - = note: expected `&'z1 [u8]` + = note: expected `&[u8]` found `&'a [u8]` note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9... --> $DIR/region-object-lifetime-in-coercion.rs:25:9 diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr index b26891a678980..a8a7e97e6acf6 100644 --- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr +++ b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr @@ -5,7 +5,7 @@ LL | want_F(bar); | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx | = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S` - found fn item `for<'a> fn(&'a S) -> &'z2 S {bar::<'_>}` + found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-nested-fns.stderr b/src/test/ui/regions/regions-nested-fns.stderr index 40e9146d6894a..9e405d83140d8 100644 --- a/src/test/ui/regions/regions-nested-fns.stderr +++ b/src/test/ui/regions/regions-nested-fns.stderr @@ -40,7 +40,7 @@ LL | | return z; LL | | })); | |_____^ = note: expected `&isize` - found `&'z13 isize` + found `&isize` error[E0312]: lifetime of reference outlives lifetime of borrowed content... --> $DIR/regions-nested-fns.rs:14:27 diff --git a/src/test/ui/regions/regions-ret-borrowed-1.stderr b/src/test/ui/regions/regions-ret-borrowed-1.stderr index b489290d9f71d..2c4769d8e3751 100644 --- a/src/test/ui/regions/regions-ret-borrowed-1.stderr +++ b/src/test/ui/regions/regions-ret-borrowed-1.stderr @@ -14,7 +14,7 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&'z0 isize` + = note: expected `&isize` found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 9:14... --> $DIR/regions-ret-borrowed-1.rs:9:14 diff --git a/src/test/ui/regions/regions-ret-borrowed.stderr b/src/test/ui/regions/regions-ret-borrowed.stderr index 6b2a041b95bc3..da560107cea99 100644 --- a/src/test/ui/regions/regions-ret-borrowed.stderr +++ b/src/test/ui/regions/regions-ret-borrowed.stderr @@ -14,7 +14,7 @@ note: ...so that the expression is assignable | LL | with(|o| o) | ^ - = note: expected `&'z0 isize` + = note: expected `&isize` found `&isize` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 12:14... --> $DIR/regions-ret-borrowed.rs:12:14 diff --git a/src/test/ui/regions/regions-trait-1.stderr b/src/test/ui/regions/regions-trait-1.stderr index 6b3c40658a73d..60ac7c09f0414 100644 --- a/src/test/ui/regions/regions-trait-1.stderr +++ b/src/test/ui/regions/regions-trait-1.stderr @@ -5,7 +5,7 @@ LL | fn get_ctxt(&self) -> &'a Ctxt { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&HasCtxt<'a>) -> &Ctxt` - found fn pointer `fn(&'z0 HasCtxt<'a>) -> &'a Ctxt` + found fn pointer `fn(&HasCtxt<'a>) -> &'a Ctxt` note: the lifetime `'a` as defined on the impl at 12:6... --> $DIR/regions-trait-1.rs:12:6 | diff --git a/src/test/ui/regions/regions-trait-object-subtyping.stderr b/src/test/ui/regions/regions-trait-object-subtyping.stderr index 271849fdef693..7478b53bd3ccc 100644 --- a/src/test/ui/regions/regions-trait-object-subtyping.stderr +++ b/src/test/ui/regions/regions-trait-object-subtyping.stderr @@ -42,7 +42,7 @@ note: ...so that the expression is assignable LL | x | ^ = note: expected `&'b mut (dyn Dummy + 'b)` - found `&'z1 mut (dyn Dummy + 'b)` + found `&mut (dyn Dummy + 'b)` error[E0308]: mismatched types --> $DIR/regions-trait-object-subtyping.rs:22:5 diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr index 0d19ea1ff2507..c14dfa3601a8c 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr @@ -54,8 +54,8 @@ LL | Opts::A(ref mut i) | Opts::B(ref i) => {} | | | first introduced with type `&mut isize` here | - = note: expected type `&'z0 mut isize` - found type `&'z1 isize` + = note: expected type `&mut isize` + found type `&isize` = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 6 previous errors diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index 8ea45e4191da7..d1960a8aab300 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -22,8 +22,8 @@ error[E0308]: mismatched types LL | test(&y); | ^^ types differ in mutability | - = note: expected mutable reference `&'z2 mut std::string::String` - found reference `&'z3 std::string::String` + = note: expected mutable reference `&mut std::string::String` + found reference `&std::string::String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:14:11 diff --git a/src/test/ui/traits/trait-impl-method-mismatch.stderr b/src/test/ui/traits/trait-impl-method-mismatch.stderr index 517da553dc0ee..52e4918624168 100644 --- a/src/test/ui/traits/trait-impl-method-mismatch.stderr +++ b/src/test/ui/traits/trait-impl-method-mismatch.stderr @@ -8,7 +8,7 @@ LL | unsafe fn jumbo(&self, x: &usize) { *self + *x; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn | = note: expected fn pointer `fn(&usize, &usize) -> usize` - found fn pointer `unsafe fn(&'z0 usize, &'z1 usize)` + found fn pointer `unsafe fn(&usize, &usize)` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.rs b/src/test/ui/traits/trait-param-without-lifetime-constraint.rs new file mode 100644 index 0000000000000..a79b74dcddead --- /dev/null +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.rs @@ -0,0 +1,20 @@ +struct Article { + proof_reader: ProofReader, +} + +struct ProofReader { + name: String, +} + +pub trait HaveRelationship { + fn get_relation(&self) -> To; +} + +impl HaveRelationship<&ProofReader> for Article { + fn get_relation(&self) -> &ProofReader { + //~^ ERROR `impl` item signature doesn't match `trait` item signature + &self.proof_reader + } +} + +fn main() {} diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr new file mode 100644 index 0000000000000..912d3a8d28de1 --- /dev/null +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -0,0 +1,18 @@ +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 + | +LL | pub trait HaveRelationship { + | -- in order for `impl` items to be able to implement the method, this type parameter might need a lifetime restriction like `To: 'a` +LL | fn get_relation(&self) -> To; + | ----------------------------- expected fn(&Article) -> &ProofReader +... +LL | fn get_relation(&self) -> &ProofReader { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Article) -> &ProofReader + | + = note: expected `fn(&Article) -> &ProofReader` + found `fn(&Article) -> &ProofReader` + = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output + +error: aborting due to previous error + diff --git a/src/test/ui/type/type-mismatch.stderr b/src/test/ui/type/type-mismatch.stderr index 7beffa0e5e493..24c71c63103d3 100644 --- a/src/test/ui/type/type-mismatch.stderr +++ b/src/test/ui/type/type-mismatch.stderr @@ -211,7 +211,7 @@ LL | want::<&Foo>(f); | expected `&Foo`, found struct `Foo` | help: consider borrowing here: `&f` | - = note: expected reference `&'z0 Foo` + = note: expected reference `&Foo` found struct `Foo` error[E0308]: mismatched types @@ -313,7 +313,7 @@ LL | want::<&Foo>(f); | expected `&Foo`, found struct `Foo` | help: consider borrowing here: `&f` | - = note: expected reference `&'z1 Foo` + = note: expected reference `&Foo` found struct `Foo` error[E0308]: mismatched types diff --git a/src/test/ui/unsafe/unsafe-trait-impl.rs b/src/test/ui/unsafe/unsafe-trait-impl.rs index 691c751a080f1..03a251be1a914 100644 --- a/src/test/ui/unsafe/unsafe-trait-impl.rs +++ b/src/test/ui/unsafe/unsafe-trait-impl.rs @@ -8,7 +8,7 @@ impl Foo for u32 { fn len(&self) -> u32 { *self } //~^ ERROR method `len` has an incompatible type for trait //~| expected fn pointer `unsafe fn(&u32) -> _` - //~| found fn pointer `fn(&'z0 u32) -> _` + //~| found fn pointer `fn(&u32) -> _` } fn main() { } diff --git a/src/test/ui/unsafe/unsafe-trait-impl.stderr b/src/test/ui/unsafe/unsafe-trait-impl.stderr index f163790eb4511..1c3d057cbc9ce 100644 --- a/src/test/ui/unsafe/unsafe-trait-impl.stderr +++ b/src/test/ui/unsafe/unsafe-trait-impl.stderr @@ -8,7 +8,7 @@ LL | fn len(&self) -> u32 { *self } | ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found normal fn | = note: expected fn pointer `unsafe fn(&u32) -> _` - found fn pointer `fn(&'z0 u32) -> _` + found fn pointer `fn(&u32) -> _` error: aborting due to previous error diff --git a/src/test/ui/wrong-mul-method-signature.stderr b/src/test/ui/wrong-mul-method-signature.stderr index cb901cdeedf0c..4c367fb9e9caf 100644 --- a/src/test/ui/wrong-mul-method-signature.stderr +++ b/src/test/ui/wrong-mul-method-signature.stderr @@ -5,7 +5,7 @@ LL | fn mul(self, s: &f64) -> Vec1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `f64`, found `&f64` | = note: expected fn pointer `fn(Vec1, f64) -> Vec1` - found fn pointer `fn(Vec1, &'z0 f64) -> Vec1` + found fn pointer `fn(Vec1, &f64) -> Vec1` error[E0053]: method `mul` has an incompatible type for trait --> $DIR/wrong-mul-method-signature.rs:33:5 From 38112321908e824a56943f8e2a461510206e2409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 22 Dec 2019 17:53:50 -0800 Subject: [PATCH 369/695] review comments --- .../trait_impl_difference.rs | 58 ++++++------------- .../mismatched_trait_impl-2.stderr | 2 +- .../mismatched_trait_impl.nll.stderr | 2 +- .../mismatched_trait_impl.stderr | 2 +- ...ime-mismatch-between-trait-and-impl.stderr | 2 +- ...t-param-without-lifetime-constraint.stderr | 4 +- 6 files changed, 24 insertions(+), 46 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 5aa55d253aa1e..7ad7e8897df38 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -63,22 +63,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_label(trait_sp, &format!("expected {:?}", expected)); let trait_fn_sig = tcx.fn_sig(trait_def_id); + // Check the `trait`'s method's output to look for type parameters that might have + // unconstrained lifetimes. If the method returns a type parameter and the `impl` has a + // borrow as the type parameter being implemented, the lifetimes will not match because + // a new lifetime is being introduced in the `impl` that is not present in the `trait`. + // Because this is confusing as hell the first time you see it, we give a short message + // explaining the situation and proposing constraining the type param with a named lifetime + // so that the `impl` will have one to tie them together. struct AssocTypeFinder(FxHashSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); - match ty.kind { - ty::Param(param) => { - self.0.insert(param); - } - _ => {} + if let ty::Param(param) = ty.kind { + self.0.insert(param); } ty.super_visit_with(self) } } let mut visitor = AssocTypeFinder(FxHashSet::default()); trait_fn_sig.output().visit_with(&mut visitor); - if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); @@ -86,8 +89,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { for param_ty in visitor.0 { if let Some(generic) = generics.get_named(param_ty.name) { err.span_label(generic.span, &format!( - "in order for `impl` items to be able to implement the method, this \ - type parameter might need a lifetime restriction like `{}: 'a`", + "for `impl` items to implement the method, this type parameter might \ + need a lifetime restriction like `{}: 'a`", param_ty.name, )); } @@ -95,46 +98,21 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - struct EarlyBoundRegionHighlighter(FxHashSet); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for EarlyBoundRegionHighlighter { - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - match *r { - ty::ReFree(free) => { - self.0.insert(free.scope); - } - ty::ReEarlyBound(bound) => { - self.0.insert(bound.def_id); - } - _ => {} - } - r.super_visit_with(self) - } - } - - let mut visitor = EarlyBoundRegionHighlighter(FxHashSet::default()); - expected.visit_with(&mut visitor); - - let note = !visitor.0.is_empty(); - - if let Some((expected, found)) = self - .tcx() + if let Some((expected, found)) = tcx .infer_ctxt() .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found })) { + // Highlighted the differences when showing the "expected/found" note. err.note_expected_found(&"", expected, &"", found); } else { // This fallback shouldn't be necessary, but let's keep it in just in case. err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); } - if note { - err.note( - "the lifetime requirements from the `trait` could not be fulfilled by the `impl`", - ); - err.help( - "verify the lifetime relationships in the `trait` and `impl` between the \ - `self` argument, the other inputs and its output", - ); - } + err.note("the lifetime requirements from the `trait` could not be satisfied by the `impl`"); + err.help( + "verify the lifetime relationships in the `trait` and `impl` between the `self` \ + argument, the other inputs and its output", + ); err.emit(); } } diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index d8a2fa14333ea..05413c3a2923a 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -11,7 +11,7 @@ LL | fn deref(&self) -> &Self::Target; | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` found `fn(&Struct) -> &dyn Trait` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index 88edf10a66f0c..c58f78b6719a1 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index dcdc6d330c0e7..4dbd4ac6a852b 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error[E0623]: lifetime mismatch diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index fa2ea83deefb7..0e56473c5b6ac 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -9,7 +9,7 @@ LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { | = note: expected `fn(&i32, &'a i32) -> &'a i32` found `fn(&i32, &i32) -> &i32` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr index 912d3a8d28de1..724062b1a589f 100644 --- a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -2,7 +2,7 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 | LL | pub trait HaveRelationship { - | -- in order for `impl` items to be able to implement the method, this type parameter might need a lifetime restriction like `To: 'a` + | -- for `impl` items to implement the method, this type parameter might need a lifetime restriction like `To: 'a` LL | fn get_relation(&self) -> To; | ----------------------------- expected fn(&Article) -> &ProofReader ... @@ -11,7 +11,7 @@ LL | fn get_relation(&self) -> &ProofReader { | = note: expected `fn(&Article) -> &ProofReader` found `fn(&Article) -> &ProofReader` - = note: the lifetime requirements from the `trait` could not be fulfilled by the `impl` + = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error From 2e2f82053ffbf23997b736cde720ca4db4207504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 27 Dec 2019 13:52:20 -0800 Subject: [PATCH 370/695] review comment: use FxIndexSet --- .../nice_region_error/trait_impl_difference.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 7ad7e8897df38..039671b982849 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -6,7 +6,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFoldable; @@ -70,7 +70,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Because this is confusing as hell the first time you see it, we give a short message // explaining the situation and proposing constraining the type param with a named lifetime // so that the `impl` will have one to tie them together. - struct AssocTypeFinder(FxHashSet); + struct AssocTypeFinder(FxIndexSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); @@ -80,7 +80,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ty.super_visit_with(self) } } - let mut visitor = AssocTypeFinder(FxHashSet::default()); + let mut visitor = AssocTypeFinder(FxIndexSet::default()); trait_fn_sig.output().visit_with(&mut visitor); if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { let parent_id = tcx.hir().get_parent_item(id); From d0d30b0a3ea6b715e275aa17ced2f7bc8d5207d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 7 Jan 2020 12:05:34 -0800 Subject: [PATCH 371/695] fix rebase --- .../nice_region_error/trait_impl_difference.rs | 6 +++--- src/test/ui/issues/issue-20831-debruijn.stderr | 4 ++-- .../regions/regions-normalize-in-where-clause-list.stderr | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 039671b982849..4019708df9828 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -1,13 +1,13 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. -use crate::hir; -use crate::hir::def_id::DefId; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; +use rustc_hir::def_id::DefId; +use rustc_hir::ItemKind; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty}; @@ -85,7 +85,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); - if let hir::ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { + if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { for param_ty in visitor.0 { if let Some(generic) = generics.get_named(param_ty.name) { err.span_label(generic.span, &format!( diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr index 160a4213a4043..e7c1dcc5d698c 100644 --- a/src/test/ui/issues/issue-20831-debruijn.stderr +++ b/src/test/ui/issues/issue-20831-debruijn.stderr @@ -87,8 +87,8 @@ note: ...so that the types are compatible | LL | fn subscribe(&mut self, t : Box::Output> + 'a>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `Publisher<'_>` - found `Publisher<'_>` + = note: expected `Publisher<'_>` + found `Publisher<'_>` error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/issue-20831-debruijn.rs:28:33 diff --git a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr index a274fd9d658a9..dc93d620ca637 100644 --- a/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr +++ b/src/test/ui/regions/regions-normalize-in-where-clause-list.stderr @@ -63,8 +63,8 @@ LL | | where <() as Project<'a, 'b>>::Item : Eq LL | | { LL | | } | |_^ - = note: expected `Project<'a, 'b>` - found `Project<'_, '_>` + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements --> $DIR/regions-normalize-in-where-clause-list.rs:22:4 @@ -87,8 +87,8 @@ note: ...so that the types are compatible | LL | fn bar<'a, 'b>() | ^^^ - = note: expected `Project<'a, 'b>` - found `Project<'_, '_>` + = note: expected `Project<'a, 'b>` + found `Project<'_, '_>` error: aborting due to 3 previous errors From 2b35247d7a80e689dee6363730807687fdf42b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 16 Feb 2020 17:59:29 -0800 Subject: [PATCH 372/695] Modify wording --- .../trait_impl_difference.rs | 83 ++++++++++++++++--- .../mismatched_trait_impl-2.stderr | 4 +- .../mismatched_trait_impl.stderr | 4 +- ...ime-mismatch-between-trait-and-impl.stderr | 4 +- ...t-param-without-lifetime-constraint.stderr | 9 +- 5 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 4019708df9828..ca925233333c1 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -2,15 +2,17 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::{Subtype, ValuePairs}; +use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; +use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::ItemKind; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -59,8 +61,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); - err.span_label(sp, &format!("found {:?}", found)); - err.span_label(trait_sp, &format!("expected {:?}", expected)); + err.span_label(sp, &format!("found `{:?}`", found)); + err.span_label(trait_sp, &format!("expected `{:?}`", expected)); let trait_fn_sig = tcx.fn_sig(trait_def_id); // Check the `trait`'s method's output to look for type parameters that might have @@ -73,7 +75,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { struct AssocTypeFinder(FxIndexSet); impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - debug!("assoc type finder ty {:?} {:?}", ty, ty.kind); if let ty::Param(param) = ty.kind { self.0.insert(param); } @@ -86,18 +87,40 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { - for param_ty in visitor.0 { + for param_ty in &visitor.0 { if let Some(generic) = generics.get_named(param_ty.name) { - err.span_label(generic.span, &format!( - "for `impl` items to implement the method, this type parameter might \ - need a lifetime restriction like `{}: 'a`", - param_ty.name, - )); + err.span_label( + generic.span, + "this type parameter might not have a lifetime compatible with the \ + `impl`", + ); } } } } + // Get the span of all the used type parameters in the method. + let assoc_item = self.tcx().associated_item(trait_def_id); + let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; + match assoc_item.kind { + ty::AssocKind::Method => { + let hir = self.tcx().hir(); + if let Some(hir_id) = hir.as_local_hir_id(assoc_item.def_id) { + if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) { + visitor.visit_fn_decl(decl); + } + } + } + _ => {} + } + for span in visitor.types { + err.span_label( + span, + "you might want to borrow this type parameter in the trait to make it match the \ + `impl`", + ); + } + if let Some((expected, found)) = tcx .infer_ctxt() .enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found })) @@ -116,3 +139,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.emit(); } } + +struct TypeParamSpanVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + types: Vec, +} + +impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { + type Map = hir::intravisit::Map<'tcx>; + + fn nested_visit_map<'this>( + &'this mut self, + ) -> hir::intravisit::NestedVisitorMap<'this, Self::Map> { + hir::intravisit::NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + } + + fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { + match arg.kind { + hir::TyKind::Slice(_) | hir::TyKind::Tup(_) | hir::TyKind::Array(..) => { + hir::intravisit::walk_ty(self, arg); + } + hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { + [segment] + if segment + .res + .map(|res| match res { + hir::def::Res::Def(hir::def::DefKind::TyParam, _) => true, + _ => false, + }) + .unwrap_or(false) => + { + self.types.push(path.span); + } + _ => {} + }, + _ => {} + } + } +} diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index 05413c3a2923a..61a8674a2310e 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -2,12 +2,12 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl-2.rs:8:5 | LL | fn deref(&self) -> &dyn Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait` | ::: $SRC_DIR/libcore/ops/deref.rs:LL:COL | LL | fn deref(&self) -> &Self::Target; - | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static) + | --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)` | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` found `fn(&Struct) -> &dyn Trait` diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 4dbd4ac6a852b..ca61029145530 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -2,10 +2,10 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl.rs:9:5 | LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; - | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32 + | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32` ... LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32` | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index 0e56473c5b6ac..53f6aae5ff6e0 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -2,10 +2,10 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5 | LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32; - | ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32 + | ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32` ... LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32` | = note: expected `fn(&i32, &'a i32) -> &'a i32` found `fn(&i32, &i32) -> &i32` diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr index 724062b1a589f..a7be2d3365c1a 100644 --- a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -2,12 +2,15 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 | LL | pub trait HaveRelationship { - | -- for `impl` items to implement the method, this type parameter might need a lifetime restriction like `To: 'a` + | -- this type parameter might not have a lifetime compatible with the `impl` LL | fn get_relation(&self) -> To; - | ----------------------------- expected fn(&Article) -> &ProofReader + | ----------------------------- + | | | + | | you might want to borrow this type parameter in the trait to make it match the `impl` + | expected `fn(&Article) -> &ProofReader` ... LL | fn get_relation(&self) -> &ProofReader { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Article) -> &ProofReader + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader` | = note: expected `fn(&Article) -> &ProofReader` found `fn(&Article) -> &ProofReader` From 500504c0bd79996784496d4ffa7a153ed5d10dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 29 Mar 2020 19:53:58 -0700 Subject: [PATCH 373/695] fix rebase --- .../nice_region_error/trait_impl_difference.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index ca925233333c1..c0046758b07f7 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -148,10 +148,8 @@ struct TypeParamSpanVisitor<'tcx> { impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { type Map = hir::intravisit::Map<'tcx>; - fn nested_visit_map<'this>( - &'this mut self, - ) -> hir::intravisit::NestedVisitorMap<'this, Self::Map> { - hir::intravisit::NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir()) } fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { From c52dbbc64354942c244c9f497e73d2e0814deaf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 13 Apr 2020 21:31:21 -0700 Subject: [PATCH 374/695] fix rebase --- .../error_reporting/nice_region_error/trait_impl_difference.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index c0046758b07f7..120594df6719b 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -146,7 +146,7 @@ struct TypeParamSpanVisitor<'tcx> { } impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { - type Map = hir::intravisit::Map<'tcx>; + type Map = rustc_middle::hir::map::Map<'tcx>; fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir()) From 7d5415b5a2faf5b8f76156eedfd66f94b91660a0 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 26 May 2020 23:14:55 -0700 Subject: [PATCH 375/695] Add additional checks for isize overflow We now perform the correct checks even if the pointer size differs between the host and target. Signed-off-by: Joe Richey --- src/librustc_middle/mir/interpret/pointer.rs | 15 +++++++++++++-- src/librustc_mir/interpret/intrinsics.rs | 5 ++--- src/test/ui/consts/offset_ub.stderr | 4 ++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/src/librustc_middle/mir/interpret/pointer.rs index 019c96bc511eb..ccad4f0a135a1 100644 --- a/src/librustc_middle/mir/interpret/pointer.rs +++ b/src/librustc_middle/mir/interpret/pointer.rs @@ -24,6 +24,12 @@ pub trait PointerArithmetic: HasDataLayout { u64::try_from(max_usize_plus_1 - 1).unwrap() } + #[inline] + fn machine_isize_min(&self) -> i64 { + let max_isize_plus_1 = 1i128 << (self.pointer_size().bits() - 1); + i64::try_from(-max_isize_plus_1).unwrap() + } + #[inline] fn machine_isize_max(&self) -> i64 { let max_isize_plus_1 = 1u128 << (self.pointer_size().bits() - 1); @@ -42,18 +48,23 @@ pub trait PointerArithmetic: HasDataLayout { #[inline] fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) { + // We do not need to check if i fits in a machine usize. If it doesn't, + // either the wrapping_add will wrap or res will not fit in a pointer. let res = val.overflowing_add(i); self.truncate_to_ptr(res) } #[inline] fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) { + // We need to make sure that i fits in a machine isize. let n = uabs(i); if i >= 0 { - self.overflowing_offset(val, n) + let (val, over) = self.overflowing_offset(val, n); + (val, over || i > self.machine_isize_max()) } else { let res = val.overflowing_sub(n); - self.truncate_to_ptr(res) + let (val, over) = self.truncate_to_ptr(res); + (val, over || i < self.machine_isize_min()) } } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 239115076bc4b..55f254f573261 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -441,9 +441,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // We cannot overflow i64 as a type's size must be <= isize::MAX. let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); // The computed offset, in bytes, cannot overflow an isize. - let offset_bytes = offset_count - .checked_mul(pointee_size) - .ok_or(err_ub_format!("inbounds pointer arithmetic: overflow computing offset"))?; + let offset_bytes = + offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?; // The offset being in bounds cannot rely on "wrapping around" the address space. // So, first rule out overflows in the pointer arithmetic. let offset_ptr = ptr.ptr_signed_offset(offset_bytes, self)?; diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index e808939682f30..0ab81cc0c5b31 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -51,7 +51,7 @@ error: any use of this value will cause an error LL | intrinsics::offset(self, count) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | inbounds pointer arithmetic: overflow computing offset + | overflowing in-bounds pointer arithmetic | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | inside `OVERFLOW` at $DIR/offset_ub.rs:11:43 | @@ -66,7 +66,7 @@ error: any use of this value will cause an error LL | intrinsics::offset(self, count) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | inbounds pointer arithmetic: overflow computing offset + | overflowing in-bounds pointer arithmetic | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44 | From 7b490903809ce5c03c83869357a68e88f8cc0799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 27 May 2020 14:08:31 +0200 Subject: [PATCH 376/695] clippy_dev: add ra_setup This takes an absolute path to a rustc repo and adds path-dependencies that point towards the respective rustc subcrates into the Cargo.tomls of the clippy and clippy_lints crate. This allows rustc-analyzer to show proper type annotations etc on rustc-internals inside the clippy repo. Usage: cargo dev ra-setup /absolute/path/to/rust/ cc https://github.com/rust-analyzer/rust-analyzer/issues/3517 cc https://github.com/rust-lang/rust-clippy/issues/5514 --- clippy_dev/src/lib.rs | 3 +- clippy_dev/src/main.rs | 16 ++++++- clippy_dev/src/ra_setup.rs | 90 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 clippy_dev/src/ra_setup.rs diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 6fdd282c6849e..5baa31d5cde0c 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -11,6 +11,7 @@ use walkdir::WalkDir; pub mod fmt; pub mod new_lint; +pub mod ra_setup; pub mod stderr_length_check; pub mod update_lints; @@ -400,7 +401,7 @@ fn test_replace_region_no_changes() { changed: false, new_lines: "123\n456\n789".to_string(), }; - let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || vec![]); + let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new); assert_eq!(expected, result); } diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index d99235f7c07a7..281037ae37c97 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -1,7 +1,7 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] use clap::{App, Arg, SubCommand}; -use clippy_dev::{fmt, new_lint, stderr_length_check, update_lints}; +use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints}; fn main() { let matches = App::new("Clippy developer tooling") @@ -87,6 +87,19 @@ fn main() { SubCommand::with_name("limit_stderr_length") .about("Ensures that stderr files do not grow longer than a certain amount of lines."), ) + .subcommand( + SubCommand::with_name("ra-setup") + .about("Alter dependencies so rust-analyzer can find rustc internals") + .arg( + Arg::with_name("rustc-repo-path") + .long("repo-path") + .short("r") + .help("The path to a rustc repo that will be used for setting the dependencies") + .takes_value(true) + .value_name("path") + .required(true), + ), + ) .get_matches(); match matches.subcommand() { @@ -115,6 +128,7 @@ fn main() { ("limit_stderr_length", _) => { stderr_length_check::check(); }, + ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), _ => {}, } } diff --git a/clippy_dev/src/ra_setup.rs b/clippy_dev/src/ra_setup.rs new file mode 100644 index 0000000000000..8617445c8a600 --- /dev/null +++ b/clippy_dev/src/ra_setup.rs @@ -0,0 +1,90 @@ +#![allow(clippy::filter_map)] + +use std::fs; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; + +// This module takes an absolute path to a rustc repo and alters the dependencies to point towards +// the respective rustc subcrates instead of using extern crate xyz. +// This allows rust analyzer to analyze rustc internals and show proper information inside clippy +// code. See https://github.com/rust-analyzer/rust-analyzer/issues/3517 and https://github.com/rust-lang/rust-clippy/issues/5514 for details + +pub fn run(rustc_path: Option<&str>) { + // we can unwrap here because the arg is required here + let rustc_path = PathBuf::from(rustc_path.unwrap()); + assert!(rustc_path.is_dir(), "path is not a directory"); + let rustc_source_basedir = rustc_path.join("src"); + assert!( + rustc_source_basedir.is_dir(), + "are you sure the path leads to a rustc repo?" + ); + + let clippy_root_manifest = fs::read_to_string("Cargo.toml").expect("failed to read ./Cargo.toml"); + let clippy_root_lib_rs = fs::read_to_string("src/driver.rs").expect("failed to read ./src/driver.rs"); + inject_deps_into_manifest( + &rustc_source_basedir, + "Cargo.toml", + &clippy_root_manifest, + &clippy_root_lib_rs, + ) + .expect("Failed to inject deps into ./Cargo.toml"); + + let clippy_lints_manifest = + fs::read_to_string("clippy_lints/Cargo.toml").expect("failed to read ./clippy_lints/Cargo.toml"); + let clippy_lints_lib_rs = + fs::read_to_string("clippy_lints/src/lib.rs").expect("failed to read ./clippy_lints/src/lib.rs"); + inject_deps_into_manifest( + &rustc_source_basedir, + "clippy_lints/Cargo.toml", + &clippy_lints_manifest, + &clippy_lints_lib_rs, + ) + .expect("Failed to inject deps into ./clippy_lints/Cargo.toml"); +} + +fn inject_deps_into_manifest( + rustc_source_dir: &PathBuf, + manifest_path: &str, + cargo_toml: &str, + lib_rs: &str, +) -> std::io::Result<()> { + let extern_crates = lib_rs + .lines() + // get the deps + .filter(|line| line.starts_with("extern crate")) + // we have something like "extern crate foo;", we only care about the "foo" + // ↓ ↓ + // extern crate rustc_middle; + .map(|s| &s[13..(s.len() - 1)]); + + let new_deps = extern_crates.map(|dep| { + // format the dependencies that are going to be put inside the Cargo.toml + format!( + "{dep} = {{ path = \"{source_path}/lib{dep}\" }}\n", + dep = dep, + source_path = rustc_source_dir.display() + ) + }); + + // format a new [dependencies]-block with the new deps we need to inject + let mut all_deps = String::from("[dependencies]\n"); + new_deps.for_each(|dep_line| { + all_deps.push_str(&dep_line); + }); + + // replace "[dependencies]" with + // [dependencies] + // dep1 = { path = ... } + // dep2 = { path = ... } + // etc + let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1); + + // println!("{}", new_manifest); + let mut file = File::create(manifest_path)?; + file.write_all(new_manifest.as_bytes())?; + + println!("Dependency paths injected: {}", manifest_path); + + Ok(()) +} From cb6408afc64cd364ccf3b8144d49b32e8403883c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 27 May 2020 19:24:09 -0700 Subject: [PATCH 377/695] Fix rebase --- .../nice_region_error/trait_impl_difference.rs | 7 ++++--- src/test/ui/error-codes/E0490.stderr | 4 ++-- .../ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr | 4 ++-- src/test/ui/issues/issue-20225.stderr | 4 ---- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 120594df6719b..8180dd5ef34f7 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } let mut visitor = AssocTypeFinder(FxIndexSet::default()); trait_fn_sig.output().visit_with(&mut visitor); - if let Some(id) = tcx.hir().as_local_hir_id(trait_def_id) { + if let Some(id) = trait_def_id.as_local().map(|id| tcx.hir().as_local_hir_id(id)) { let parent_id = tcx.hir().get_parent_item(id); let trait_item = tcx.hir().expect_item(parent_id); if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { @@ -103,9 +103,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let assoc_item = self.tcx().associated_item(trait_def_id); let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; match assoc_item.kind { - ty::AssocKind::Method => { + ty::AssocKind::Fn => { let hir = self.tcx().hir(); - if let Some(hir_id) = hir.as_local_hir_id(assoc_item.def_id) { + if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| hir.as_local_hir_id(id)) + { if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) { visitor.visit_fn_decl(decl); } diff --git a/src/test/ui/error-codes/E0490.stderr b/src/test/ui/error-codes/E0490.stderr index 03fce213605e3..9ba5bc330ea93 100644 --- a/src/test/ui/error-codes/E0490.stderr +++ b/src/test/ui/error-codes/E0490.stderr @@ -58,8 +58,8 @@ note: ...so that the expression is assignable | LL | let x: &'a _ = &y; | ^^ - = note: expected `&'a &()` - found `&'a &'b ()` + = note: expected `&'a &()` + found `&'a &'b ()` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6... --> $DIR/E0490.rs:1:6 | diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index c58f78b6719a1..908a81bedb0ca 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -2,10 +2,10 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl.rs:9:5 | LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; - | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32 + | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32` ... LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32` | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr index 133dbc554c089..3bcc50ded8425 100644 --- a/src/test/ui/issues/issue-20225.stderr +++ b/src/test/ui/issues/issue-20225.stderr @@ -8,8 +8,6 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(&Foo, (T,))` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_mut` has an incompatible type for trait --> $DIR/issue-20225.rs:11:3 @@ -21,8 +19,6 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(&mut Foo, (T,))` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_once` has an incompatible type for trait --> $DIR/issue-20225.rs:18:3 From f213acf4db81a33308ab2d53b5927108d63a2d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 27 May 2020 20:58:05 -0700 Subject: [PATCH 378/695] review comments: change wording and visual output --- .../trait_impl_difference.rs | 63 +++++-------------- .../mismatched_trait_impl-2.stderr | 2 +- .../mismatched_trait_impl.nll.stderr | 2 +- .../mismatched_trait_impl.stderr | 2 +- ...ime-mismatch-between-trait-and-impl.stderr | 2 +- ...t-param-without-lifetime-constraint.stderr | 14 ++--- 6 files changed, 26 insertions(+), 59 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 8180dd5ef34f7..1b6e5c2116b39 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -4,16 +4,13 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; -use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::ItemKind; use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_span::{MultiSpan, Span}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. @@ -63,41 +60,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); err.span_label(sp, &format!("found `{:?}`", found)); err.span_label(trait_sp, &format!("expected `{:?}`", expected)); - let trait_fn_sig = tcx.fn_sig(trait_def_id); - - // Check the `trait`'s method's output to look for type parameters that might have - // unconstrained lifetimes. If the method returns a type parameter and the `impl` has a - // borrow as the type parameter being implemented, the lifetimes will not match because - // a new lifetime is being introduced in the `impl` that is not present in the `trait`. - // Because this is confusing as hell the first time you see it, we give a short message - // explaining the situation and proposing constraining the type param with a named lifetime - // so that the `impl` will have one to tie them together. - struct AssocTypeFinder(FxIndexSet); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for AssocTypeFinder { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - if let ty::Param(param) = ty.kind { - self.0.insert(param); - } - ty.super_visit_with(self) - } - } - let mut visitor = AssocTypeFinder(FxIndexSet::default()); - trait_fn_sig.output().visit_with(&mut visitor); - if let Some(id) = trait_def_id.as_local().map(|id| tcx.hir().as_local_hir_id(id)) { - let parent_id = tcx.hir().get_parent_item(id); - let trait_item = tcx.hir().expect_item(parent_id); - if let ItemKind::Trait(_, _, generics, _, _) = &trait_item.kind { - for param_ty in &visitor.0 { - if let Some(generic) = generics.get_named(param_ty.name) { - err.span_label( - generic.span, - "this type parameter might not have a lifetime compatible with the \ - `impl`", - ); - } - } - } - } // Get the span of all the used type parameters in the method. let assoc_item = self.tcx().associated_item(trait_def_id); @@ -114,11 +76,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } _ => {} } - for span in visitor.types { - err.span_label( + let mut type_param_span: MultiSpan = + visitor.types.iter().cloned().collect::>().into(); + for &span in &visitor.types { + type_param_span.push_span_label( span, - "you might want to borrow this type parameter in the trait to make it match the \ - `impl`", + "consider borrowing this type parameter in the trait".to_string(), ); } @@ -132,11 +95,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // This fallback shouldn't be necessary, but let's keep it in just in case. err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); } - err.note("the lifetime requirements from the `trait` could not be satisfied by the `impl`"); - err.help( - "verify the lifetime relationships in the `trait` and `impl` between the `self` \ - argument, the other inputs and its output", + err.span_help( + type_param_span, + "the lifetime requirements from the `impl` do not correspond to the requirements in \ + the `trait`", ); + if visitor.types.is_empty() { + err.help( + "verify the lifetime relationships in the `trait` and `impl` between the `self` \ + argument, the other inputs and its output", + ); + } err.emit(); } } diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index 61a8674a2310e..b93d98ca39f47 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -11,7 +11,7 @@ LL | fn deref(&self) -> &Self::Target; | = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` found `fn(&Struct) -> &dyn Trait` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index 908a81bedb0ca..149c2aeb958c0 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index ca61029145530..9a0bd827850cf 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -9,7 +9,7 @@ LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { | = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` found `fn(&i32, &u32, &u32) -> &u32` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error[E0623]: lifetime mismatch diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr index 53f6aae5ff6e0..060e6954403c0 100644 --- a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -9,7 +9,7 @@ LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { | = note: expected `fn(&i32, &'a i32) -> &'a i32` found `fn(&i32, &i32) -> &i32` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output error: aborting due to previous error diff --git a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr index a7be2d3365c1a..4942dbe480ba3 100644 --- a/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr +++ b/src/test/ui/traits/trait-param-without-lifetime-constraint.stderr @@ -1,21 +1,19 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/trait-param-without-lifetime-constraint.rs:14:5 | -LL | pub trait HaveRelationship { - | -- this type parameter might not have a lifetime compatible with the `impl` LL | fn get_relation(&self) -> To; - | ----------------------------- - | | | - | | you might want to borrow this type parameter in the trait to make it match the `impl` - | expected `fn(&Article) -> &ProofReader` + | ----------------------------- expected `fn(&Article) -> &ProofReader` ... LL | fn get_relation(&self) -> &ProofReader { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader` | = note: expected `fn(&Article) -> &ProofReader` found `fn(&Article) -> &ProofReader` - = note: the lifetime requirements from the `trait` could not be satisfied by the `impl` - = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output +help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + --> $DIR/trait-param-without-lifetime-constraint.rs:10:31 + | +LL | fn get_relation(&self) -> To; + | ^^ consider borrowing this type parameter in the trait error: aborting due to previous error From cd6a8cae2aa07bd456a1816196e3c9aa2fcb72d6 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Thu, 28 May 2020 01:11:46 -0400 Subject: [PATCH 379/695] FIx off-by-one in char::steps_between --- src/libcore/iter/range.rs | 2 +- src/libcore/tests/iter.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 5db790e491c2d..fc4454ede3588 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -408,7 +408,7 @@ unsafe impl Step for char { let start = start as u32; let end = end as u32; if start <= end { - let count = end - start + 1; + let count = end - start; if start < 0xD800 && 0xE000 <= end { usize::try_from(count - 0x800).ok() } else { diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 6605249f18004..c5d636ac8da55 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1939,7 +1939,9 @@ fn test_char_range() { assert!(('\0'..=char::MAX).rev().eq((0..=char::MAX as u32).filter_map(char::from_u32).rev())); assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2); + assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2))); assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1); + assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1))); } #[test] From e069524c4848e6d4b24866d6725509fdf67f371d Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 28 May 2020 16:43:03 +0900 Subject: [PATCH 380/695] Add test for #66930 --- src/test/ui/mir/issue-66930.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/ui/mir/issue-66930.rs diff --git a/src/test/ui/mir/issue-66930.rs b/src/test/ui/mir/issue-66930.rs new file mode 100644 index 0000000000000..5f9eb2bf437fd --- /dev/null +++ b/src/test/ui/mir/issue-66930.rs @@ -0,0 +1,11 @@ +// check-pass +// compile-flags: --emit=mir,link +// Regression test for #66930, this ICE requires `--emit=mir` flag. + +static UTF8_CHAR_WIDTH: [u8; 0] = []; + +pub fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize +} + +fn main() {} From 804e9e546dbf246b671542a3813d38ee56e14a28 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 24 May 2020 16:03:11 +0100 Subject: [PATCH 381/695] mir: adjust conditional in recursion limit check This commit adjusts the condition used in the recursion limit check of the monomorphization collector, from `>` to `>=`. In #67552, the test case had infinite indirect recursion, repeating a handful of functions (from the perspective of the monomorphization collector): `rec` -> `identity` -> `Iterator::count` -> `Iterator::fold` -> `Iterator::next` -> `rec`. During this process, `resolve_associated_item` was invoked for `Iterator::fold` (during the construction of an `Instance`), and ICE'd due to substitutions needing inference. However, previous iterations of this recursion would have called this function for `Iterator::fold` - and did! - and succeeded in doing so (trivially checkable from debug logging, `()` is present where `_` is in the substs of the failing execution). The expected outcome of this test case would be a recursion limit error (which is present when the `identity` fn indirection is removed), and the recursion depth of `rec` is increasing (other functions finish collecting their neighbours and thus have their recursion depths reset). When the ICE occurs, the recursion depth of `rec` is 256 (which matches the recursion limit), which suggests perhaps that a different part of the compiler is using a `>=` comparison and returning a different result on this recursion rather than what it returned in every previous recursion, thus stopping the monomorphization collector from reporting an error on the next recursion, where `recursion_depth_of_rec > 256` would have been true. With grep and some educated guesses, we can determine that the recursion limit check at line 818 in `src/librustc_trait_selection/traits/project.rs` is the other check that is using a different comparison. Modifying either comparison to be `>` or `>=` respectively will fix the error, but changing the monomorphization collector produces the nicer error. Signed-off-by: David Wood --- src/librustc_mir/monomorphize/collector.rs | 2 +- .../ui/infinite/infinite-instantiation.stderr | 2 +- src/test/ui/issues/issue-67552.rs | 30 +++++++++++++++++++ src/test/ui/issues/issue-67552.stderr | 14 +++++++++ src/test/ui/issues/issue-8727.stderr | 2 +- ...-38591-non-regular-dropck-recursion.stderr | 2 +- src/test/ui/recursion/recursion.stderr | 2 +- 7 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issues/issue-67552.rs create mode 100644 src/test/ui/issues/issue-67552.stderr diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index c75e8414e8cca..1c5c13f843d7b 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -430,7 +430,7 @@ fn check_recursion_limit<'tcx>( // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. - if adjusted_recursion_depth > tcx.sess.recursion_limit() { + if adjusted_recursion_depth >= tcx.sess.recursion_limit() { let error = format!("reached the recursion limit while instantiating `{}`", instance); if let Some(def_id) = def_id.as_local() { let hir_id = tcx.hir().as_local_hir_id(def_id); diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index ae81c680a7b65..f1c04447986b0 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/infinite-instantiation.rs:25:1 | LL | / fn function(counter: usize, t: T) { diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs new file mode 100644 index 0000000000000..1400c6f97b605 --- /dev/null +++ b/src/test/ui/issues/issue-67552.rs @@ -0,0 +1,30 @@ +// build-fail + +fn main() { + rec(Empty); +} + +struct Empty; + +impl Iterator for Empty { + type Item = (); + fn next<'a>(&'a mut self) -> core::option::Option<()> { + None + } +} + +fn identity(x: T) -> T { + x +} + +fn rec(mut it: T) +//~^ ERROR reached the recursion limit while instantiating +where + T: Iterator, +{ + if () == () { + T::count(it); + } else { + rec(identity(&mut it)) + } +} diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr new file mode 100644 index 0000000000000..97ad76e207d04 --- /dev/null +++ b/src/test/ui/issues/issue-67552.stderr @@ -0,0 +1,14 @@ +error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>` + --> $DIR/issue-67552.rs:20:1 + | +LL | / fn rec(mut it: T) +LL | | +LL | | where +LL | | T: Iterator, +... | +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index ee0672c598d5c..8f581a358e1e9 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -9,7 +9,7 @@ LL | generic::>(); = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-8727.rs:6:1 | LL | / fn generic() { diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index de6df4cd0268c..d64149d1437fe 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` +error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` error: aborting due to previous error diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index 1a65b0e84f6a3..ded8b3f87db62 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/recursion.rs:15:1 | LL | / fn test (n:isize, i:isize, first:T, second:T) ->isize { From a54ed872cb79529195f4b02910be823a75f3da22 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 26 May 2020 19:48:08 +0100 Subject: [PATCH 382/695] standardize limit comparisons with `Limit` type This commit introduces a `Limit` type which is used to ensure that all comparisons against limits within the compiler are consistent (which can result in ICEs if they aren't). Signed-off-by: David Wood --- src/librustc_error_codes/error_codes/E0055.md | 2 +- src/librustc_expand/base.rs | 4 +- src/librustc_expand/expand.rs | 7 +-- src/librustc_middle/middle/limits.rs | 8 +-- src/librustc_middle/ty/layout.rs | 3 +- src/librustc_mir/const_eval/machine.rs | 5 +- src/librustc_mir/interpret/eval_context.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 4 +- src/librustc_session/session.rs | 54 ++++++++++++++++--- .../traits/project.rs | 9 ++-- .../traits/query/normalize.rs | 4 +- src/librustc_trait_selection/traits/select.rs | 2 +- src/librustc_traits/dropck_outlives.rs | 2 +- src/librustc_ty/needs_drop.rs | 5 +- src/librustc_typeck/check/autoderef.rs | 2 +- .../ui/did_you_mean/recursion_limit.stderr | 3 +- .../did_you_mean/recursion_limit_deref.stderr | 2 +- .../dropck_no_diverge_on_nonregular_1.stderr | 4 +- .../dropck_no_diverge_on_nonregular_2.stderr | 4 +- .../dropck_no_diverge_on_nonregular_3.stderr | 6 +-- src/test/ui/error-codes/E0055.rs | 2 +- src/test/ui/error-codes/E0055.stderr | 2 +- src/test/ui/error-codes/E0275.stderr | 3 +- .../ui/infinite/infinite-instantiation.stderr | 2 +- src/test/ui/issues/issue-18400.stderr | 1 + src/test/ui/issues/issue-20413.stderr | 6 ++- src/test/ui/issues/issue-23122-2.stderr | 8 +-- src/test/ui/issues/issue-38940.rs | 2 +- src/test/ui/issues/issue-38940.stderr | 2 +- src/test/ui/issues/issue-67552.stderr | 2 +- src/test/ui/issues/issue-8727.stderr | 2 +- ...-38591-non-regular-dropck-recursion.stderr | 2 +- src/test/ui/recursion/recursion.stderr | 2 +- 33 files changed, 108 insertions(+), 60 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0055.md b/src/librustc_error_codes/error_codes/E0055.md index d5b863081a616..223ba40002986 100644 --- a/src/librustc_error_codes/error_codes/E0055.md +++ b/src/librustc_error_codes/error_codes/E0055.md @@ -6,7 +6,7 @@ recursion limit (which can be set via the `recursion_limit` attribute). For a somewhat artificial example: ```compile_fail,E0055 -#![recursion_limit="5"] +#![recursion_limit="4"] struct Foo; diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 649aac488fcb3..eeb30e2ced99b 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, ErrorReported}; use rustc_parse::{self, parser, MACRO_ARGUMENTS}; -use rustc_session::parse::ParseSess; +use rustc_session::{parse::ParseSess, Limit}; use rustc_span::def_id::DefId; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind}; @@ -941,7 +941,7 @@ pub struct ExpansionData { pub struct ExtCtxt<'a> { pub parse_sess: &'a ParseSess, pub ecfg: expand::ExpansionConfig<'a>, - pub reduced_recursion_limit: Option, + pub reduced_recursion_limit: Option, pub root_path: PathBuf, pub resolver: &'a mut dyn Resolver, pub current_expansion: ExpansionData, diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index b505302f62501..09ba64204c5c3 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -24,6 +24,7 @@ use rustc_parse::validate_attr; use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; +use rustc_session::Limit; use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{FileName, Span, DUMMY_SP}; @@ -664,7 +665,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ) -> ExpandResult { let recursion_limit = self.cx.reduced_recursion_limit.unwrap_or(self.cx.ecfg.recursion_limit); - if self.cx.current_expansion.depth > recursion_limit { + if !recursion_limit.value_within_limit(self.cx.current_expansion.depth) { if self.cx.reduced_recursion_limit.is_none() { self.error_recursion_limit_reached(); } @@ -1784,7 +1785,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { pub struct ExpansionConfig<'feat> { pub crate_name: String, pub features: Option<&'feat Features>, - pub recursion_limit: usize, + pub recursion_limit: Limit, pub trace_mac: bool, pub should_test: bool, // If false, strip `#[test]` nodes pub keep_macs: bool, @@ -1795,7 +1796,7 @@ impl<'feat> ExpansionConfig<'feat> { ExpansionConfig { crate_name, features: None, - recursion_limit: 1024, + recursion_limit: Limit::new(1024), trace_mac: false, should_test: false, keep_macs: false, diff --git a/src/librustc_middle/middle/limits.rs b/src/librustc_middle/middle/limits.rs index 19c056925cf92..85198482bd380 100644 --- a/src/librustc_middle/middle/limits.rs +++ b/src/librustc_middle/middle/limits.rs @@ -8,7 +8,7 @@ use crate::bug; use rustc_ast::ast; use rustc_data_structures::sync::OnceCell; -use rustc_session::Session; +use rustc_session::{Limit, Session}; use rustc_span::symbol::{sym, Symbol}; use std::num::IntErrorKind; @@ -22,7 +22,7 @@ pub fn update_limits(sess: &Session, krate: &ast::Crate) { fn update_limit( sess: &Session, krate: &ast::Crate, - limit: &OnceCell, + limit: &OnceCell, name: Symbol, default: usize, ) { @@ -34,7 +34,7 @@ fn update_limit( if let Some(s) = attr.value_str() { match s.as_str().parse() { Ok(n) => { - limit.set(n).unwrap(); + limit.set(Limit::new(n)).unwrap(); return; } Err(e) => { @@ -62,5 +62,5 @@ fn update_limit( } } } - limit.set(default).unwrap(); + limit.set(Limit::new(default)).unwrap(); } diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 5566e187c0c5c..e93abd3390a2d 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -187,10 +187,9 @@ fn layout_raw<'tcx>( query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Result<&'tcx Layout, LayoutError<'tcx>> { ty::tls::with_related_context(tcx, move |icx| { - let rec_limit = tcx.sess.recursion_limit.get().copied().unwrap(); let (param_env, ty) = query.into_parts(); - if icx.layout_depth > rec_limit { + if !tcx.sess.recursion_limit().value_within_limit(icx.layout_depth) { tcx.sess.fatal(&format!("overflow representing the type `{}`", ty)); } diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 7c1ab261eb9c4..dc13126df0e4c 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -10,6 +10,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_ast::ast::Mutability; use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; +use rustc_session::Limit; use rustc_span::symbol::Symbol; use crate::interpret::{ @@ -109,8 +110,8 @@ pub struct MemoryExtra { } impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(super) fn new(const_eval_limit: usize) -> Self { - CompileTimeInterpreter { steps_remaining: const_eval_limit, stack: Vec::new() } + pub(super) fn new(const_eval_limit: Limit) -> Self { + CompileTimeInterpreter { steps_remaining: const_eval_limit.0, stack: Vec::new() } } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 4f91257e2ef83..6497e211de316 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -651,7 +651,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { M::after_stack_push(self)?; info!("ENTERING({}) {}", self.frame_idx(), self.frame().instance); - if self.stack().len() > self.tcx.sess.recursion_limit() { + if !self.tcx.sess.recursion_limit().value_within_limit(self.stack().len()) { throw_exhaust!(StackFrameLimitReached) } else { Ok(()) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 1c5c13f843d7b..767eacd2c1ace 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -430,7 +430,7 @@ fn check_recursion_limit<'tcx>( // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. - if adjusted_recursion_depth >= tcx.sess.recursion_limit() { + if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { let error = format!("reached the recursion limit while instantiating `{}`", instance); if let Some(def_id) = def_id.as_local() { let hir_id = tcx.hir().as_local_hir_id(def_id); @@ -463,7 +463,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // which means that rustc basically hangs. // // Bail out in these cases to avoid that bad user experience. - if type_length > tcx.sess.type_length_limit() { + if !tcx.sess.type_length_limit().value_within_limit(type_length) { // The instance name is already known to be too long for rustc. // Show only the first and last 32 characters to avoid blasting // the user's terminal with thousands of lines of type-name. diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index f2f02cb649463..a943cf3b67497 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -29,8 +29,10 @@ use rustc_target::spec::{Target, TargetTriple, TlsModel}; use std::cell::{self, RefCell}; use std::env; +use std::fmt; use std::io::Write; use std::num::NonZeroU32; +use std::ops::{Div, Mul}; use std::path::PathBuf; use std::str::FromStr; use std::sync::Arc; @@ -55,6 +57,46 @@ pub enum CtfeBacktrace { Immediate, } +/// New-type wrapper around `usize` for representing limits. Ensures that comparisons against +/// limits are consistent throughout the compiler. +#[derive(Clone, Copy, Debug)] +pub struct Limit(pub usize); + +impl Limit { + /// Create a new limit from a `usize`. + pub fn new(value: usize) -> Self { + Limit(value) + } + + /// Check that `value` is within the limit. Ensures that the same comparisons are used + /// throughout the compiler, as mismatches can cause ICEs, see #72540. + pub fn value_within_limit(&self, value: usize) -> bool { + value <= self.0 + } +} + +impl fmt::Display for Limit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Div for Limit { + type Output = Limit; + + fn div(self, rhs: usize) -> Self::Output { + Limit::new(self.0 / rhs) + } +} + +impl Mul for Limit { + type Output = Limit; + + fn mul(self, rhs: usize) -> Self::Output { + Limit::new(self.0 * rhs) + } +} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { @@ -89,13 +131,13 @@ pub struct Session { /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. - pub recursion_limit: OnceCell, + pub recursion_limit: OnceCell, /// The maximum length of types during monomorphization. - pub type_length_limit: OnceCell, + pub type_length_limit: OnceCell, /// The maximum blocks a const expression can evaluate. - pub const_eval_limit: OnceCell, + pub const_eval_limit: OnceCell, incr_comp_session: OneThread>, /// Used for incremental compilation tests. Will only be populated if @@ -255,15 +297,15 @@ impl Session { self.crate_types.set(crate_types).expect("`crate_types` was initialized twice") } - pub fn recursion_limit(&self) -> usize { + pub fn recursion_limit(&self) -> Limit { self.recursion_limit.get().copied().unwrap() } - pub fn type_length_limit(&self) -> usize { + pub fn type_length_limit(&self) -> Limit { self.type_length_limit.get().copied().unwrap() } - pub fn const_eval_limit(&self) -> usize { + pub fn const_eval_limit(&self) -> Limit { self.const_eval_limit.get().copied().unwrap() } diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index cd5d0be003aaf..1126480b02a0d 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -333,10 +333,10 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { Reveal::All => { let recursion_limit = self.tcx().sess.recursion_limit(); - if self.depth >= recursion_limit { + if !recursion_limit.value_within_limit(self.depth) { let obligation = Obligation::with_depth( self.cause.clone(), - recursion_limit, + recursion_limit.0, self.param_env, ty, ); @@ -522,7 +522,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // But for now, let's classify this as an overflow: let recursion_limit = selcx.tcx().sess.recursion_limit(); let obligation = - Obligation::with_depth(cause, recursion_limit, param_env, projection_ty); + Obligation::with_depth(cause, recursion_limit.0, param_env, projection_ty); selcx.infcx().report_overflow_error(&obligation, false); } Err(ProjectionCacheEntry::NormalizedTy(ty)) => { @@ -814,8 +814,7 @@ fn project_type<'cx, 'tcx>( ) -> Result, ProjectionTyError<'tcx>> { debug!("project(obligation={:?})", obligation); - let recursion_limit = selcx.tcx().sess.recursion_limit(); - if obligation.recursion_depth >= recursion_limit { + if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); } diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index 008ca8d526dd3..3e7749356d212 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -109,10 +109,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { Reveal::All => { let recursion_limit = self.tcx().sess.recursion_limit(); - if self.anon_depth >= recursion_limit { + if !recursion_limit.value_within_limit(self.anon_depth) { let obligation = Obligation::with_depth( self.cause.clone(), - recursion_limit, + recursion_limit.0, self.param_env, ty, ); diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index b27fba2f82ba5..23e3eea021059 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -919,7 +919,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &Obligation<'tcx, T>, error_obligation: &Obligation<'tcx, V>, ) -> Result<(), OverflowError> { - if obligation.recursion_depth >= self.infcx.tcx.sess.recursion_limit() { + if !self.infcx.tcx.sess.recursion_limit().value_within_limit(obligation.recursion_depth) { match self.query_mode { TraitQueryMode::Standard => { self.infcx().report_overflow_error(error_obligation, true); diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index fb9c0d7f99013..11c48559bd683 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -163,7 +163,7 @@ fn dtorck_constraint_for_ty<'tcx>( ) -> Result<(), NoSolution> { debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty); - if depth >= tcx.sess.recursion_limit() { + if !tcx.sess.recursion_limit().value_within_limit(depth) { constraints.overflows.push(ty); return Ok(()); } diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs index 1b059fa3dbdf0..c54704e7877f1 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/src/librustc_ty/needs_drop.rs @@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_session::Limit; use rustc_span::DUMMY_SP; type NeedsDropResult = Result; @@ -30,7 +31,7 @@ struct NeedsDropTypes<'tcx, F> { /// if it needs drop. If the result depends on whether some other types /// need drop we push them onto the stack. unchecked_tys: Vec<(Ty<'tcx>, usize)>, - recursion_limit: usize, + recursion_limit: Limit, adt_components: F, } @@ -66,7 +67,7 @@ where let tcx = self.tcx; while let Some((ty, level)) = self.unchecked_tys.pop() { - if level > self.recursion_limit { + if !self.recursion_limit.value_within_limit(level) { // Not having a `Span` isn't great. But there's hopefully some other // recursion limit error as well. tcx.sess.span_err( diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index d4c01a82e0aa5..73d4e2b78206d 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { return Some((self.cur_ty, 0)); } - if self.steps.len() >= tcx.sess.recursion_limit() { + if !tcx.sess.recursion_limit().value_within_limit(self.steps.len()) { if !self.silence_errors { report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty); } diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index 45cb054b80c91..c9a6d42b5cc22 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `J: std::marker::Send` +error[E0275]: overflow evaluating the requirement `K: std::marker::Send` --> $DIR/recursion_limit.rs:34:5 | LL | fn is_send() { } @@ -8,6 +8,7 @@ LL | is_send::(); | ^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit`) + = note: required because it appears within the type `J` = note: required because it appears within the type `I` = note: required because it appears within the type `H` = note: required because it appears within the type `G` diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.stderr b/src/test/ui/did_you_mean/recursion_limit_deref.stderr index e8d11530b08aa..8339cc291cf30 100644 --- a/src/test/ui/did_you_mean/recursion_limit_deref.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_deref.stderr @@ -1,4 +1,4 @@ -error[E0055]: reached the recursion limit while auto-dereferencing `I` +error[E0055]: reached the recursion limit while auto-dereferencing `J` --> $DIR/recursion_limit_deref.rs:50:22 | LL | let x: &Bottom = &t; diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr index dd0c438f421c6..5df69e4649df5 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr @@ -4,7 +4,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | let ft = | ^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for FingerTree --> $DIR/dropck_no_diverge_on_nonregular_1.rs:25:9 @@ -12,7 +12,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | FingerTree::Single(1); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 2 previous errors diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr index 769d5aed664f3..d34097d401004 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr @@ -4,7 +4,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | let ft = | ^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for FingerTree --> $DIR/dropck_no_diverge_on_nonregular_2.rs:24:9 @@ -12,7 +12,7 @@ error[E0320]: overflow while adding drop-check rules for FingerTree LL | FingerTree::Single(1); | ^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 2 previous errors diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr index de8afdcc7cdab..1c810df242389 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr @@ -4,7 +4,7 @@ error[E0320]: overflow while adding drop-check rules for std::option::Option>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for std::option::Option> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:9 @@ -12,7 +12,7 @@ error[E0320]: overflow while adding drop-check rules for std::option::Option); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error[E0320]: overflow while adding drop-check rules for Wrapper --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:14 @@ -20,7 +20,7 @@ error[E0320]: overflow while adding drop-check rules for Wrapper LL | Some(Wrapper::Simple::); | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0055.rs b/src/test/ui/error-codes/E0055.rs index b525575d98d46..fd5804bbc2a59 100644 --- a/src/test/ui/error-codes/E0055.rs +++ b/src/test/ui/error-codes/E0055.rs @@ -1,4 +1,4 @@ -#![recursion_limit="5"] +#![recursion_limit="4"] struct Foo; impl Foo { diff --git a/src/test/ui/error-codes/E0055.stderr b/src/test/ui/error-codes/E0055.stderr index 01411e585abdd..1b8c5760e65bf 100644 --- a/src/test/ui/error-codes/E0055.stderr +++ b/src/test/ui/error-codes/E0055.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | ref_foo.foo(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="10"]` attribute to your crate (`E0055`) + = help: consider adding a `#![recursion_limit="8"]` attribute to your crate (`E0055`) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index a9fd0564ff548..2692fe6945e09 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` +error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/E0275.rs:5:33 | LL | trait Foo {} @@ -8,6 +8,7 @@ LL | impl Foo for T where Bar: Foo {} | ^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`) + = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/infinite/infinite-instantiation.stderr b/src/test/ui/infinite/infinite-instantiation.stderr index f1c04447986b0..ae81c680a7b65 100644 --- a/src/test/ui/infinite/infinite-instantiation.stderr +++ b/src/test/ui/infinite/infinite-instantiation.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/infinite-instantiation.rs:25:1 | LL | / fn function(counter: usize, t: T) { diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index 57067ad51759a..ed9137ce396cf 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -133,6 +133,7 @@ LL | 0.contains(bits); = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` + = note: required because of the requirements on the impl of `Set<&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[&[_]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>` for `{integer}` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index ad33eef07cba5..a3eb4fec70f32 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -6,7 +6,7 @@ LL | struct NoData; | = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` -error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` +error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:36 | LL | trait Foo { @@ -16,6 +16,7 @@ LL | impl Foo for T where NoData: Foo { | ^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` @@ -144,7 +145,7 @@ LL | impl Foo for T where NoData: Foo { = note: required because of the requirements on the impl of `Foo` for `NoData>` = note: required because of the requirements on the impl of `Foo` for `NoData` -error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` +error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:36 | LL | trait Foo { @@ -154,6 +155,7 @@ LL | impl Foo for T where NoData: Foo { | ^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` = note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index 7625e30498ac3..c4032b27edcbd 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,20 +1,20 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` --> $DIR/issue-23122-2.rs:7:15 | LL | impl Next for GetNext { | ^^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) - = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` + = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized` --> $DIR/issue-23122-2.rs:9:5 | LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) - = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` + = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-38940.rs b/src/test/ui/issues/issue-38940.rs index 1c785949547e5..3f10fc017a73f 100644 --- a/src/test/ui/issues/issue-38940.rs +++ b/src/test/ui/issues/issue-38940.rs @@ -42,5 +42,5 @@ fn main() { let t = Top::new(); let x: &Bottom = &t; //~^ ERROR mismatched types - //~| ERROR reached the recursion limit while auto-dereferencing `I` + //~| ERROR reached the recursion limit while auto-dereferencing `J` } diff --git a/src/test/ui/issues/issue-38940.stderr b/src/test/ui/issues/issue-38940.stderr index 36117278fd814..0671cede73bbe 100644 --- a/src/test/ui/issues/issue-38940.stderr +++ b/src/test/ui/issues/issue-38940.stderr @@ -1,4 +1,4 @@ -error[E0055]: reached the recursion limit while auto-dereferencing `I` +error[E0055]: reached the recursion limit while auto-dereferencing `J` --> $DIR/issue-38940.rs:43:22 | LL | let x: &Bottom = &t; diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr index 97ad76e207d04..881f9d221d6ae 100644 --- a/src/test/ui/issues/issue-67552.stderr +++ b/src/test/ui/issues/issue-67552.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>` +error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut Empty>` --> $DIR/issue-67552.rs:20:1 | LL | / fn rec(mut it: T) diff --git a/src/test/ui/issues/issue-8727.stderr b/src/test/ui/issues/issue-8727.stderr index 8f581a358e1e9..ee0672c598d5c 100644 --- a/src/test/ui/issues/issue-8727.stderr +++ b/src/test/ui/issues/issue-8727.stderr @@ -9,7 +9,7 @@ LL | generic::>(); = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-8727.rs:6:1 | LL | / fn generic() { diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index d64149d1437fe..de6df4cd0268c 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` +error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::> - shim(Some(S))` error: aborting due to previous error diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index ded8b3f87db62..1a65b0e84f6a3 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,4 +1,4 @@ -error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` +error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/recursion.rs:15:1 | LL | / fn test (n:isize, i:isize, first:T, second:T) ->isize { From 52ed89ae8c264d8885bfda4f79033289db459c02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 May 2020 10:31:38 +0200 Subject: [PATCH 383/695] from_u32_unchecked: check validity when debug assertions are enabled --- src/libcore/char/convert.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 315020bac5850..87c56c4b0a105 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -99,7 +99,7 @@ pub fn from_u32(i: u32) -> Option { #[inline] #[stable(feature = "char_from_unchecked", since = "1.5.0")] pub unsafe fn from_u32_unchecked(i: u32) -> char { - transmute(i) + if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { transmute(i) } } #[stable(feature = "char_convert", since = "1.13.0")] @@ -218,7 +218,7 @@ impl TryFrom for char { Err(CharTryFromError(())) } else { // SAFETY: checked that it's a legal unicode value - Ok(unsafe { from_u32_unchecked(i) }) + Ok(unsafe { transmute(i) }) } } } From bcf57d8f20830683d0b66e231010903146a298e7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 28 May 2020 14:51:12 +0200 Subject: [PATCH 384/695] Fix escape key handling --- src/librustdoc/html/static/main.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 9869c50fbb0cf..c349b59e562a9 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -81,6 +81,7 @@ function getSearchElement() { var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") === "true"; var search_input = getSearchInput(); + var searchTimeout = null; // On the search screen, so you remain on the last tab you opened. // @@ -344,6 +345,10 @@ function getSearchElement() { if (hasClass(help, "hidden") === false) { displayHelp(false, ev, help); } else if (hasClass(search, "hidden") === false) { + if (searchTimeout !== null) { + clearTimeout(searchTimeout); + searchTimeout = null; + } ev.preventDefault(); hideSearchResults(search); document.title = titleBeforeSearch; @@ -1799,7 +1804,6 @@ function getSearchElement() { } function startSearch() { - var searchTimeout; var callback = function() { clearTimeout(searchTimeout); if (search_input.value.length === 0) { @@ -1815,7 +1819,10 @@ function getSearchElement() { search_input.oninput = callback; document.getElementsByClassName("search-form")[0].onsubmit = function(e) { e.preventDefault(); - clearTimeout(searchTimeout); + if (searchTimeout !== null) { + clearTimeout(searchTimeout); + searchTimeout = null; + } search(); }; search_input.onchange = function(e) { @@ -1824,7 +1831,10 @@ function getSearchElement() { return; } // Do NOT e.preventDefault() here. It will prevent pasting. - clearTimeout(searchTimeout); + if (searchTimeout !== null) { + clearTimeout(searchTimeout); + searchTimeout = null; + } // zero-timeout necessary here because at the time of event handler execution the // pasted content is not in the input field yet. Shouldn’t make any difference for // change, though. From a0e9f9bd0dca39ccff47baedffa94aca74911a86 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 28 May 2020 15:45:24 +0200 Subject: [PATCH 385/695] Merge commit '7ea7cd165ad6705603852771bf82cc2fd6560db5' into clippyup2 --- .github/workflows/clippy.yml | 2 +- .github/workflows/clippy_bors.yml | 10 +- CHANGELOG.md | 1 + CONTRIBUTING.md | 100 +++++---- clippy_dev/src/new_lint.rs | 190 +++++++++++------- clippy_lints/Cargo.toml | 2 + clippy_lints/src/attrs.rs | 75 ++++--- clippy_lints/src/cargo_common_metadata.rs | 1 + clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/lib.rs | 17 +- clippy_lints/src/matches.rs | 74 ++++++- clippy_lints/src/methods/mod.rs | 34 +++- clippy_lints/src/misc_early.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/multiple_crate_versions.rs | 58 ++++-- clippy_lints/src/mut_reference.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/new_without_default.rs | 128 +++--------- clippy_lints/src/non_expressive_names.rs | 15 +- clippy_lints/src/ptr.rs | 10 +- clippy_lints/src/ranges.rs | 30 ++- clippy_lints/src/redundant_field_names.rs | 4 + .../src/trivially_copy_pass_by_ref.rs | 2 +- clippy_lints/src/useless_conversion.rs | 79 ++++++-- clippy_lints/src/utils/conf.rs | 6 +- clippy_lints/src/utils/inspector.rs | 8 +- clippy_lints/src/utils/mod.rs | 2 +- clippy_lints/src/utils/paths.rs | 2 + clippy_lints/src/utils/sugg.rs | 2 +- doc/adding_lints.md | 25 ++- doc/common_tools_writing_lints.md | 152 ++++++++++++++ rustc_tools_util/LICENSE-APACHE | 1 + rustc_tools_util/LICENSE-MIT | 1 + setup-toolchain.sh | 2 +- src/driver.rs | 2 +- src/lintlist/mod.rs | 11 +- tests/compile-test.rs | 150 ++++++++++---- .../cargo_common_metadata/fail/Cargo.toml | 4 + .../cargo_common_metadata/fail/src/main.rs | 4 + .../fail/src/main.stderr | 18 ++ .../cargo_common_metadata/pass/Cargo.toml | 11 + .../cargo_common_metadata/pass/src/main.rs | 4 + .../5041_allow_dev_build/Cargo.toml | 17 ++ .../5041_allow_dev_build/src/main.rs | 4 + .../multiple_crate_versions/fail/Cargo.toml | 8 + .../multiple_crate_versions/fail/src/main.rs | 4 + .../fail/src/main.stderr | 6 + .../multiple_crate_versions/pass/Cargo.toml | 8 + .../multiple_crate_versions/pass/src/main.rs | 4 + tests/ui-cargo/update-all-references.sh | 18 ++ tests/ui-cargo/update-references.sh | 38 ++++ .../wildcard_dependencies/fail/Cargo.toml | 7 + .../wildcard_dependencies/fail/src/main.rs | 4 + .../fail/src/main.stderr | 6 + .../wildcard_dependencies/pass/Cargo.toml | 7 + .../wildcard_dependencies/pass/src/main.rs | 4 + tests/ui/auxiliary/proc_macro_attr.rs | 37 ++++ tests/ui/cognitive_complexity.rs | 2 +- tests/ui/cognitive_complexity_attr_used.rs | 4 +- tests/ui/empty_line_after_outer_attribute.rs | 19 +- .../empty_line_after_outer_attribute.stderr | 12 +- tests/ui/future_not_send.stderr | 26 ++- tests/ui/match_wild_err_arm.stderr | 8 +- .../match_wildcard_for_single_variants.fixed | 59 ++++++ .../ui/match_wildcard_for_single_variants.rs | 59 ++++++ .../match_wildcard_for_single_variants.stderr | 28 +++ tests/ui/new_without_default.rs | 11 + tests/ui/new_without_default.stderr | 35 +++- tests/ui/option_option.rs | 25 +++ tests/ui/option_option.stderr | 8 +- tests/ui/or_fun_call.fixed | 9 + tests/ui/or_fun_call.rs | 9 + tests/ui/ptr_arg.rs | 32 ++- tests/ui/ptr_offset_with_cast.fixed | 12 +- tests/ui/ptr_offset_with_cast.rs | 12 +- tests/ui/ptr_offset_with_cast.stderr | 12 +- tests/ui/reversed_empty_ranges_fixable.fixed | 7 +- tests/ui/reversed_empty_ranges_fixable.rs | 7 +- tests/ui/reversed_empty_ranges_fixable.stderr | 16 +- tests/ui/reversed_empty_ranges_unfixable.rs | 1 - .../ui/reversed_empty_ranges_unfixable.stderr | 10 +- tests/ui/useless_conversion.stderr | 20 +- tests/ui/useless_conversion_try.rs | 42 ++++ tests/ui/useless_conversion_try.stderr | 79 ++++++++ 84 files changed, 1550 insertions(+), 433 deletions(-) create mode 100644 doc/common_tools_writing_lints.md create mode 120000 rustc_tools_util/LICENSE-APACHE create mode 120000 rustc_tools_util/LICENSE-MIT create mode 100644 tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml create mode 100644 tests/ui-cargo/cargo_common_metadata/fail/src/main.rs create mode 100644 tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr create mode 100644 tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml create mode 100644 tests/ui-cargo/cargo_common_metadata/pass/src/main.rs create mode 100644 tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml create mode 100644 tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs create mode 100644 tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml create mode 100644 tests/ui-cargo/multiple_crate_versions/fail/src/main.rs create mode 100644 tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr create mode 100644 tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml create mode 100644 tests/ui-cargo/multiple_crate_versions/pass/src/main.rs create mode 100755 tests/ui-cargo/update-all-references.sh create mode 100755 tests/ui-cargo/update-references.sh create mode 100644 tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml create mode 100644 tests/ui-cargo/wildcard_dependencies/fail/src/main.rs create mode 100644 tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr create mode 100644 tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml create mode 100644 tests/ui-cargo/wildcard_dependencies/pass/src/main.rs create mode 100644 tests/ui/auxiliary/proc_macro_attr.rs create mode 100644 tests/ui/match_wildcard_for_single_variants.fixed create mode 100644 tests/ui/match_wildcard_for_single_variants.rs create mode 100644 tests/ui/match_wildcard_for_single_variants.stderr create mode 100644 tests/ui/useless_conversion_try.rs create mode 100644 tests/ui/useless_conversion_try.stderr diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 8edf0c23860aa..5fa8009a8b42c 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -49,7 +49,7 @@ jobs: run: cargo update - name: Cache cargo dir - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cargo key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 6675a1029bbc8..3958ba012467b 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -94,7 +94,7 @@ jobs: run: cargo update - name: Cache cargo dir - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cargo key: ${{ runner.os }}-${{ matrix.host }}-${{ hashFiles('Cargo.lock') }} @@ -190,7 +190,7 @@ jobs: run: cargo update - name: Cache cargo dir - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cargo key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} @@ -269,7 +269,7 @@ jobs: run: cargo update - name: Cache cargo dir - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cargo key: ${{ runner.os }}-x86_64-unknown-linux-gnu-${{ hashFiles('Cargo.lock') }} @@ -312,7 +312,7 @@ jobs: name: bors test finished if: github.event.pusher.name == 'bors' && success() runs-on: ubuntu-latest - needs: [base, integration] + needs: [changelog, base, integration_build, integration] steps: - name: Mark the job as successful @@ -322,7 +322,7 @@ jobs: name: bors test finished if: github.event.pusher.name == 'bors' && (failure() || cancelled()) runs-on: ubuntu-latest - needs: [base, integration] + needs: [changelog, base, integration_build, integration] steps: - name: Mark the job as a failure diff --git a/CHANGELOG.md b/CHANGELOG.md index 583c32ca9e032..2ac9057199ff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1439,6 +1439,7 @@ Released 2018-09-13 [`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms [`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm +[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50a5ee8bbf3c8..0f47ac98fd20a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -155,47 +155,77 @@ That's why the `else_if_without_else` example uses the `register_early_pass` fun ## Fixing build failures caused by Rust -Clippy will sometimes fail to build from source because building it depends on unstable internal Rust features. Most of -the times we have to adapt to the changes and only very rarely there's an actual bug in Rust. Fixing build failures -caused by Rust updates, can be a good way to learn about Rust internals. +Clippy currently gets built with `rustc` of the `rust-lang/rust` `master` +branch. Most of the times we have to adapt to the changes and only very rarely +there's an actual bug in Rust. + +If you decide to make Clippy work again with a Rust commit that breaks it, you +have to sync the `rust-lang/rust-clippy` repository with the `subtree` copy of +Clippy in the `rust-lang/rust` repository. + +For general information about `subtree`s in the Rust repository see [Rust's +`CONTRIBUTING.md`][subtree]. + +Here is a TL;DR version of the sync process (all of the following commands have +to be run inside the `rust` directory): + +1. Clone the [`rust-lang/rust`] repository +2. Sync the changes to the rust-copy of Clippy to your Clippy fork: + ```bash + # Make sure to change `your-github-name` to your github name in the following command + git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust + ``` + _Note:_ This will directly push to the remote repository. You can also push + to your local copy by replacing the remote address with `/path/to/rust-clippy` + directory. + + _Note:_ Most of the time you have to create a merge commit in the + `rust-clippy` repo (this has to be done in the Clippy repo, not in the + rust-copy of Clippy): + ```bash + git fetch origin && git fetch upstream + git checkout sync-from-rust + git merge upstream/master + ``` +3. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to + accelerate the process ping the `@rust-lang/clippy` team in your PR and/or + ~~annoy~~ ask them in the [Discord] channel.) +4. Sync the `rust-lang/rust-clippy` master to the rust-copy of Clippy: + ```bash + git checkout -b sync-from-clippy + git subtree pull -P src/tools/clippy https://github.com/rust-lang/rust-clippy master + ``` +5. Open a PR to [`rust-lang/rust`] + +Also, you may want to define remotes, so you don't have to type out the remote +addresses on every sync. You can do this with the following commands (these +commands still have to be run inside the `rust` directory): -In order to find out why Clippy does not work properly with a new Rust commit, you can use the [rust-toolstate commit -history][toolstate_commit_history]. You will then have to look for the last commit that contains -`test-pass -> build-fail` or `test-pass -> test-fail` for the `clippy-driver` component. -[Here][toolstate_commit] is an example. - -The commit message contains a link to the PR. The PRs are usually small enough to discover the breaking API change and -if they are bigger, they likely include some discussion that may help you to fix Clippy. - -To check if Clippy is available for a specific target platform, you can check -the [rustup component history][rustup_component_history]. - -If you decide to make Clippy work again with a Rust commit that breaks it, -you probably want to install the latest Rust from master locally and run Clippy -using that version of Rust. - -You can set up the master toolchain by running `./setup-toolchain.sh`. That script will install -[rustup-toolchain-install-master][rtim] and master toolchain, then run `rustup override set master`. - -After fixing the build failure on this repository, we can submit a pull request -to [`rust-lang/rust`] to fix the toolstate. +```bash +# Set clippy-upstream remote for pulls +$ git remote add clippy-upstream https://github.com/rust-lang/rust-clippy +# Make sure to not push to the upstream repo +$ git remote set-url --push clippy-upstream DISABLED +# Set clippy-origin remote to your fork for pushes +$ git remote add clippy-origin git@github.com:your-github-name/rust-clippy +# Set a local remote +$ git remote add clippy-local /path/to/rust-clippy +``` -To submit a pull request, you should follow these steps: +You can then sync with the remote names from above, e.g.: ```bash -# Assuming you already cloned the rust-lang/rust repo and you're in the correct directory -git submodule update --remote src/tools/clippy -cargo update -p clippy -git add -u -git commit -m "Update Clippy" -./x.py test -i --stage 1 src/tools/clippy # This is optional and should succeed anyway -# Open a PR in rust-lang/rust +$ git subtree push -P src/tools/clippy clippy-local sync-from-rust ``` -[rustup_component_history]: https://rust-lang.github.io/rustup-components-history -[toolstate_commit_history]: https://github.com/rust-lang-nursery/rust-toolstate/commits/master -[toolstate_commit]: https://github.com/rust-lang-nursery/rust-toolstate/commit/aad74d8294e198a7cf8ac81a91aebb7f3bbcf727 -[rtim]: https://github.com/kennytm/rustup-toolchain-install-master +_Note:_ The first time running `git subtree push` a cache has to be built. This +involves going through the complete Clippy history once. For this you have to +increase the stack limit though, which you can do with `ulimit -s 60000`. For +this to work, you will need the fix of `git subtree` available +[here][gitgitgadget-pr]. + +[gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 +[subtree]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust ## Issue and PR triage diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 44b2a5383d211..c0b2dac2f60ff 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,91 +1,111 @@ use crate::clippy_project_root; -use std::fs::{File, OpenOptions}; -use std::io; +use std::fs::{self, OpenOptions}; use std::io::prelude::*; -use std::io::ErrorKind; -use std::path::Path; +use std::io::{self, ErrorKind}; +use std::path::{Path, PathBuf}; + +struct LintData<'a> { + pass: &'a str, + name: &'a str, + category: &'a str, + project_root: PathBuf, +} + +trait Context { + fn context>(self, text: C) -> Self; +} + +impl Context for io::Result { + fn context>(self, text: C) -> Self { + match self { + Ok(t) => Ok(t), + Err(e) => { + let message = format!("{}: {}", text.as_ref(), e); + Err(io::Error::new(ErrorKind::Other, message)) + }, + } + } +} -/// Creates files required to implement and test a new lint and runs `update_lints`. +/// Creates the files required to implement and test a new lint and runs `update_lints`. /// /// # Errors /// -/// This function errors, if the files couldn't be created -pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> Result<(), io::Error> { - let pass = pass.expect("`pass` argument is validated by clap"); - let lint_name = lint_name.expect("`name` argument is validated by clap"); - let category = category.expect("`category` argument is validated by clap"); - - match open_files(lint_name) { - Ok((mut test_file, mut lint_file)) => { - let (pass_type, pass_lifetimes, pass_import, context_import) = match pass { - "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), - "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"), - _ => { - unreachable!("`pass_type` should only ever be `early` or `late`!"); - }, - }; - - let camel_case_name = to_camel_case(lint_name); - - if let Err(e) = test_file.write_all(get_test_file_contents(lint_name).as_bytes()) { - return Err(io::Error::new( - ErrorKind::Other, - format!("Could not write to test file: {}", e), - )); - }; - - if let Err(e) = lint_file.write_all( - get_lint_file_contents( - pass_type, - pass_lifetimes, - lint_name, - &camel_case_name, - category, - pass_import, - context_import, - ) - .as_bytes(), - ) { - return Err(io::Error::new( - ErrorKind::Other, - format!("Could not write to lint file: {}", e), - )); - } - Ok(()) +/// This function errors out if the files couldn't be created or written to. +pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> io::Result<()> { + let lint = LintData { + pass: pass.expect("`pass` argument is validated by clap"), + name: lint_name.expect("`name` argument is validated by clap"), + category: category.expect("`category` argument is validated by clap"), + project_root: clippy_project_root(), + }; + + create_lint(&lint).context("Unable to create lint implementation")?; + create_test(&lint).context("Unable to create a test for the new lint") +} + +fn create_lint(lint: &LintData) -> io::Result<()> { + let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass { + "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), + "late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"), + _ => { + unreachable!("`pass_type` should only ever be `early` or `late`!"); }, - Err(e) => Err(io::Error::new( - ErrorKind::Other, - format!("Unable to create lint: {}", e), - )), - } + }; + + let camel_case_name = to_camel_case(lint.name); + let lint_contents = get_lint_file_contents( + pass_type, + pass_lifetimes, + lint.name, + &camel_case_name, + lint.category, + pass_import, + context_import, + ); + + let lint_path = format!("clippy_lints/src/{}.rs", lint.name); + write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes()) } -fn open_files(lint_name: &str) -> Result<(File, File), io::Error> { - let project_root = clippy_project_root(); +fn create_test(lint: &LintData) -> io::Result<()> { + fn create_project_layout>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> { + let mut path = location.into().join(case); + fs::create_dir(&path)?; + write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?; - let test_file_path = project_root.join("tests").join("ui").join(format!("{}.rs", lint_name)); - let lint_file_path = project_root - .join("clippy_lints") - .join("src") - .join(format!("{}.rs", lint_name)); + path.push("src"); + fs::create_dir(&path)?; + let header = format!("// compile-flags: --crate-name={}", lint_name); + write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?; - if Path::new(&test_file_path).exists() { - return Err(io::Error::new( - ErrorKind::AlreadyExists, - format!("test file {:?} already exists", test_file_path), - )); + Ok(()) } - if Path::new(&lint_file_path).exists() { - return Err(io::Error::new( - ErrorKind::AlreadyExists, - format!("lint file {:?} already exists", lint_file_path), - )); + + if lint.category == "cargo" { + let relative_test_dir = format!("tests/ui-cargo/{}", lint.name); + let test_dir = lint.project_root.join(relative_test_dir); + fs::create_dir(&test_dir)?; + + create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?; + create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint") + } else { + let test_path = format!("tests/ui/{}.rs", lint.name); + let test_contents = get_test_file_contents(lint.name, None); + write_file(lint.project_root.join(test_path), test_contents) } +} - let test_file = OpenOptions::new().write(true).create_new(true).open(test_file_path)?; - let lint_file = OpenOptions::new().write(true).create_new(true).open(lint_file_path)?; +fn write_file, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { + fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { + OpenOptions::new() + .write(true) + .create_new(true) + .open(path)? + .write_all(contents) + } - Ok((test_file, lint_file)) + inner(path.as_ref(), contents.as_ref()).context(format!("writing to file: {}", path.as_ref().display())) } fn to_camel_case(name: &str) -> String { @@ -100,8 +120,8 @@ fn to_camel_case(name: &str) -> String { .collect() } -fn get_test_file_contents(lint_name: &str) -> String { - format!( +fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String { + let mut contents = format!( "#![warn(clippy::{})] fn main() {{ @@ -109,6 +129,26 @@ fn main() {{ }} ", lint_name + ); + + if let Some(header) = header_commands { + contents = format!("{}\n{}", header, contents); + } + + contents +} + +fn get_manifest_contents(lint_name: &str, hint: &str) -> String { + format!( + r#" +# {} + +[package] +name = "{}" +version = "0.1.0" +publish = false +"#, + hint, lint_name ) } diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 1c0be72783462..76baf27fb2dbf 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -32,6 +32,8 @@ semver = "0.9.0" # NOTE: cargo requires serde feat in its url dep # see url = { version = "2.1.0", features = ["serde"] } +quote = "1" +syn = { version = "1", features = ["full"] } [features] deny-warnings = [] diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 64abc9fdc7174..41f125d48398f 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -248,7 +248,6 @@ declare_lint_pass!(Attributes => [ INLINE_ALWAYS, DEPRECATED_SEMVER, USELESS_ATTRIBUTE, - EMPTY_LINE_AFTER_OUTER_ATTR, UNKNOWN_CLIPPY_LINTS, ]); @@ -480,36 +479,6 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib } for attr in attrs { - let attr_item = if let AttrKind::Normal(ref attr) = attr.kind { - attr - } else { - continue; - }; - - if attr.style == AttrStyle::Outer { - if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) { - return; - } - - let begin_of_attr_to_item = Span::new(attr.span.lo(), span.lo(), span.ctxt()); - let end_of_attr_to_item = Span::new(attr.span.hi(), span.lo(), span.ctxt()); - - if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) { - let lines = snippet.split('\n').collect::>(); - let lines = without_block_comments(lines); - - if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - span_lint( - cx, - EMPTY_LINE_AFTER_OUTER_ATTR, - begin_of_attr_to_item, - "Found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - ); - } - } - } - if let Some(values) = attr.meta_item_list() { if values.len() != 1 || !attr.check_name(sym!(inline)) { continue; @@ -551,15 +520,57 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool { } } -declare_lint_pass!(EarlyAttributes => [DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS]); +declare_lint_pass!(EarlyAttributes => [ + DEPRECATED_CFG_ATTR, + MISMATCHED_TARGET_OS, + EMPTY_LINE_AFTER_OUTER_ATTR, +]); impl EarlyLintPass for EarlyAttributes { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::ast::Item) { + check_empty_line_after_outer_attr(cx, item); + } + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { check_deprecated_cfg_attr(cx, attr); check_mismatched_target_os(cx, attr); } } +fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::ast::Item) { + for attr in &item.attrs { + let attr_item = if let AttrKind::Normal(ref attr) = attr.kind { + attr + } else { + return; + }; + + if attr.style == AttrStyle::Outer { + if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) { + return; + } + + let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt()); + let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt()); + + if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) { + let lines = snippet.split('\n').collect::>(); + let lines = without_block_comments(lines); + + if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { + span_lint( + cx, + EMPTY_LINE_AFTER_OUTER_ATTR, + begin_of_attr_to_item, + "Found an empty line after an outer attribute. \ + Perhaps you forgot to add a `!` to make it an inner attribute?", + ); + } + } + } + } +} + fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { if_chain! { // check cfg_attr diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 782da249808d0..16b46423c8f01 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -23,6 +23,7 @@ declare_clippy_lint! { /// [package] /// name = "clippy" /// version = "0.0.212" + /// authors = ["Someone "] /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" /// repository = "https://github.com/rust-lang/rust-clippy" /// readme = "README.md" diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 3a52b1d3fc20b..4c604cd01075e 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatLiteral { let type_suffix = match lit_float_ty { LitFloatType::Suffixed(FloatTy::F32) => Some("f32"), LitFloatType::Suffixed(FloatTy::F64) => Some("f64"), - _ => None + LitFloatType::Unsuffixed => None }; let (is_whole, mut float_str) = match fty { FloatTy::F32 => { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e0787ac0887e4..902f3d56c1e4f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -346,13 +346,8 @@ mod reexport { /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. /// /// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &Conf) { +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { store.register_pre_expansion_pass(|| box write::Write::default()); - store.register_pre_expansion_pass(|| box redundant_field_names::RedundantFieldNames); - let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; - store.register_pre_expansion_pass(move || box non_expressive_names::NonExpressiveNames { - single_char_binding_names_threshold, - }); store.register_pre_expansion_pass(|| box attrs::EarlyAttributes); store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro); } @@ -638,6 +633,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &matches::MATCH_OVERLAPPING_ARM, &matches::MATCH_REF_PATS, &matches::MATCH_SINGLE_BINDING, + &matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS, &matches::MATCH_WILD_ERR_ARM, &matches::REST_PAT_IN_FULLY_BOUND_STRUCTS, &matches::SINGLE_MATCH, @@ -1065,6 +1061,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); + store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); + let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; + store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { + single_char_binding_names_threshold, + }); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1139,6 +1140,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(¯o_use::MACRO_USE_IMPORTS), LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::MATCH_BOOL), + LintId::of(&matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), + LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::SINGLE_MATCH_ELSE), LintId::of(&methods::FILTER_MAP), LintId::of(&methods::FILTER_MAP_NEXT), @@ -1283,7 +1286,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), LintId::of(&matches::MATCH_SINGLE_BINDING), - LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::SINGLE_MATCH), LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM), @@ -1474,7 +1476,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH), LintId::of(&matches::MATCH_OVERLAPPING_ARM), LintId::of(&matches::MATCH_REF_PATS), - LintId::of(&matches::MATCH_WILD_ERR_ARM), LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index bbf14374a1f7f..94380acfcfd4c 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -168,7 +168,7 @@ declare_clippy_lint! { /// **What it does:** Checks for arm which matches all errors with `Err(_)` /// and take drastic actions like `panic!`. /// - /// **Why is this bad?** It is generally a bad practice, just like + /// **Why is this bad?** It is generally a bad practice, similar to /// catching all exceptions in java with `catch(Exception)` /// /// **Known problems:** None. @@ -182,7 +182,7 @@ declare_clippy_lint! { /// } /// ``` pub MATCH_WILD_ERR_ARM, - style, + pedantic, "a `match` with `Err(_)` arm and take drastic actions" } @@ -220,7 +220,7 @@ declare_clippy_lint! { /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); /// match x { - /// A => {}, + /// Foo::A(_) => {}, /// _ => {}, /// } /// ``` @@ -229,6 +229,40 @@ declare_clippy_lint! { "a wildcard enum match arm using `_`" } +declare_clippy_lint! { + /// **What it does:** Checks for wildcard enum matches for a single variant. + /// + /// **Why is this bad?** New enum variants added by library updates can be missed. + /// + /// **Known problems:** Suggested replacements may not use correct path to enum + /// if it's not present in the current scope. + /// + /// **Example:** + /// + /// ```rust + /// # enum Foo { A, B, C } + /// # let x = Foo::B; + /// match x { + /// Foo::A => {}, + /// Foo::B => {}, + /// _ => {}, + /// } + /// ``` + /// Use instead: + /// ```rust + /// # enum Foo { A, B, C } + /// # let x = Foo::B; + /// match x { + /// Foo::A => {}, + /// Foo::B => {}, + /// Foo::C => {}, + /// } + /// ``` + pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + pedantic, + "a wildcard enum match for a single variant" +} + declare_clippy_lint! { /// **What it does:** Checks for wildcard pattern used with others patterns in same match arm. /// @@ -356,6 +390,7 @@ impl_lint_pass!(Matches => [ MATCH_WILD_ERR_ARM, MATCH_AS_REF, WILDCARD_ENUM_MATCH_ARM, + MATCH_WILDCARD_FOR_SINGLE_VARIANTS, WILDCARD_IN_OR_PATTERNS, MATCH_SINGLE_BINDING, INFALLIBLE_DESTRUCTURING_MATCH, @@ -676,7 +711,7 @@ fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) arm.pat.span, &format!("`Err({})` matches all errors", &ident_bind_name), None, - "match each error separately or use the error output", + "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable", ); } } @@ -729,9 +764,21 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_ if let QPath::Resolved(_, p) = path { missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); } - } else if let PatKind::TupleStruct(ref path, ..) = arm.pat.kind { + } else if let PatKind::TupleStruct(ref path, ref patterns, ..) = arm.pat.kind { if let QPath::Resolved(_, p) = path { - missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); + // Some simple checks for exhaustive patterns. + // There is a room for improvements to detect more cases, + // but it can be more expensive to do so. + let is_pattern_exhaustive = |pat: &&Pat<'_>| { + if let PatKind::Wild | PatKind::Binding(.., None) = pat.kind { + true + } else { + false + } + }; + if patterns.iter().all(is_pattern_exhaustive) { + missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id())); + } } } } @@ -766,6 +813,19 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_ } } + if suggestion.len() == 1 { + // No need to check for non-exhaustive enum as in that case len would be greater than 1 + span_lint_and_sugg( + cx, + MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + wildcard_span, + message, + "try this", + suggestion[0].clone(), + Applicability::MaybeIncorrect, + ) + }; + span_lint_and_sugg( cx, WILDCARD_ENUM_MATCH_ARM, @@ -773,7 +833,7 @@ fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_ message, "try this", suggestion.join(" | "), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ) } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 810a226b50d2a..52ca962e7ef97 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1496,17 +1496,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { if let ty::Opaque(def_id, _) = ret_ty.kind { // one of the associated types must be Self for predicate in cx.tcx.predicates_of(def_id).predicates { - match predicate.0.kind() { - ty::PredicateKind::Projection(poly_projection_predicate) => { - let binder = poly_projection_predicate.ty(); - let associated_type = binder.skip_binder(); - - // walk the associated type and check for Self - if contains_self_ty(associated_type) { - return; - } - }, - _ => {}, + if let ty::PredicateKind::Projection(poly_projection_predicate) = predicate.0.kind() { + let binder = poly_projection_predicate.ty(); + let associated_type = binder.skip_binder(); + + // walk the associated type and check for Self + if contains_self_ty(associated_type) { + return; + } } } } @@ -1617,6 +1614,21 @@ fn lint_or_fun_call<'a, 'tcx>( or_has_args: bool, span: Span, ) { + if let hir::ExprKind::MethodCall(ref path, _, ref args) = &arg.kind { + if path.ident.as_str() == "len" { + let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0])); + + match ty.kind { + ty::Slice(_) | ty::Array(_, _) => return, + _ => (), + } + + if match_type(cx, ty, &paths::VEC) { + return; + } + } + } + // (path, fn_has_argument, methods, suffix) let know_types: &[(&[_], _, &[_], _)] = &[ (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 62ee051624b48..552222eba2ee2 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -379,7 +379,7 @@ impl EarlyLintPass for MiscEarlyLints { let left_binding = match left { BindingMode::ByRef(Mutability::Mut) => "ref mut ", BindingMode::ByRef(Mutability::Not) => "ref ", - _ => "", + BindingMode::ByValue(..) => "", }; if let PatKind::Wild = right.kind { diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 4301157e16440..9cfc8d1913497 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn { return; } }, - _ => return, + FnKind::Closure(..) => return, } let mir = cx.tcx.optimized_mir(def_id); diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index ed85d0315bd25..b6770804e1801 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -1,11 +1,14 @@ //! lint on multiple versions of a crate being used use crate::utils::{run_lints, span_lint}; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::{Crate, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::DUMMY_SP; +use cargo_metadata::{DependencyKind, MetadataCommand, Node, Package, PackageId}; +use if_chain::if_chain; use itertools::Itertools; declare_clippy_lint! { @@ -39,30 +42,61 @@ impl LateLintPass<'_, '_> for MultipleCrateVersions { return; } - let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().exec() { + let metadata = if let Ok(metadata) = MetadataCommand::new().exec() { metadata } else { span_lint(cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, "could not read cargo metadata"); - return; }; + let local_name = cx.tcx.crate_name(LOCAL_CRATE).as_str(); let mut packages = metadata.packages; packages.sort_by(|a, b| a.name.cmp(&b.name)); - for (name, group) in &packages.into_iter().group_by(|p| p.name.clone()) { - let group: Vec = group.collect(); + if_chain! { + if let Some(resolve) = &metadata.resolve; + if let Some(local_id) = packages + .iter() + .find_map(|p| if p.name == *local_name { Some(&p.id) } else { None }); + then { + for (name, group) in &packages.iter().group_by(|p| p.name.clone()) { + let group: Vec<&Package> = group.collect(); + + if group.len() <= 1 { + continue; + } - if group.len() > 1 { - let versions = group.into_iter().map(|p| p.version).join(", "); + if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) { + let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect(); + versions.sort(); + let versions = versions.iter().join(", "); - span_lint( - cx, - MULTIPLE_CRATE_VERSIONS, - DUMMY_SP, - &format!("multiple versions for dependency `{}`: {}", name, versions), - ); + span_lint( + cx, + MULTIPLE_CRATE_VERSIONS, + DUMMY_SP, + &format!("multiple versions for dependency `{}`: {}", name, versions), + ); + } + } } } } } + +fn is_normal_dep(nodes: &[Node], local_id: &PackageId, dep_id: &PackageId) -> bool { + fn depends_on(node: &Node, dep_id: &PackageId) -> bool { + node.deps.iter().any(|dep| { + dep.pkg == *dep_id + && dep + .dep_kinds + .iter() + .any(|info| matches!(info.kind, DependencyKind::Normal)) + }) + } + + nodes + .iter() + .filter(|node| depends_on(node, dep_id)) + .any(|node| node.id == *local_id || is_normal_dep(nodes, local_id, &node.id)) +} diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index e5680482e5bfb..67a1ac78a6777 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Detects giving a mutable reference to a function that only + /// **What it does:** Detects passing a mutable reference to a function that only /// requires an immutable reference. /// /// **Why is this bad?** The immutable reference rules out all other references diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 1621c7f947c33..218b0d27f7486 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { } }, FnKind::Method(..) => (), - _ => return, + FnKind::Closure(..) => return, } // Exclude non-inherent impls diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index a599667b8d8a8..e556e5d59c188 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -1,27 +1,20 @@ use crate::utils::paths; use crate::utils::sugg::DiagnosticBuilderExt; -use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_hir_and_then}; +use crate::utils::{get_trait_def_id, return_ty, same_tys, span_lint_hir_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::DefId; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for types with a `fn new() -> Self` method and no /// implementation of /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html). /// - /// It detects both the case when a manual - /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) - /// implementation is required and also when it can be created with - /// `#[derive(Default)]` - /// /// **Why is this bad?** The user might expect to be able to use /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the /// type can be constructed without arguments. @@ -40,46 +33,17 @@ declare_clippy_lint! { /// } /// ``` /// - /// Instead, use: + /// To fix the lint, and a `Default` implementation that delegates to `new`: /// /// ```ignore /// struct Foo(Bar); /// /// impl Default for Foo { /// fn default() -> Self { - /// Foo(Bar::new()) + /// Foo::new() /// } /// } /// ``` - /// - /// Or, if - /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) - /// can be derived by `#[derive(Default)]`: - /// - /// ```rust - /// struct Foo; - /// - /// impl Foo { - /// fn new() -> Self { - /// Foo - /// } - /// } - /// ``` - /// - /// Instead, use: - /// - /// ```rust - /// #[derive(Default)] - /// struct Foo; - /// - /// impl Foo { - /// fn new() -> Self { - /// Foo - /// } - /// } - /// ``` - /// - /// You can also have `new()` call `Default::default()`. pub NEW_WITHOUT_DEFAULT, style, "`fn new() -> Self` method without `Default` implementation" @@ -126,8 +90,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { return; } if sig.decl.inputs.is_empty() && name == sym!(new) && cx.access_levels.is_reachable(id) { - let self_did = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); - let self_ty = cx.tcx.type_of(self_did); + let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); + let self_ty = cx.tcx.type_of(self_def_id); if_chain! { if same_tys(cx, self_ty, return_ty(cx, id)); if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); @@ -148,56 +112,35 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { // generics if_chain! { if let Some(ref impling_types) = self.impling_types; - if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def(); - if let Some(self_def_id) = self_def.did.as_local(); + if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def(); + if let Some(self_local_did) = self_def.did.as_local(); then { - let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_def_id); + let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); if impling_types.contains(&self_id) { return; } } } - if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) { - span_lint_hir_and_then( - cx, - NEW_WITHOUT_DEFAULT, - id, - impl_item.span, - &format!( - "you should consider deriving a `Default` implementation for `{}`", - self_ty - ), - |diag| { - diag.suggest_item_with_attr( - cx, - sp, - "try this", - "#[derive(Default)]", - Applicability::MaybeIncorrect, - ); - }); - } else { - span_lint_hir_and_then( - cx, - NEW_WITHOUT_DEFAULT, - id, - impl_item.span, - &format!( - "you should consider adding a `Default` implementation for `{}`", - self_ty - ), - |diag| { - diag.suggest_prepend_item( - cx, - item.span, - "try this", - &create_new_without_default_suggest_msg(self_ty), - Applicability::MaybeIncorrect, - ); - }, - ); - } + span_lint_hir_and_then( + cx, + NEW_WITHOUT_DEFAULT, + id, + impl_item.span, + &format!( + "you should consider adding a `Default` implementation for `{}`", + self_ty + ), + |diag| { + diag.suggest_prepend_item( + cx, + item.span, + "try this", + &create_new_without_default_suggest_msg(self_ty), + Applicability::MaybeIncorrect, + ); + }, + ); } } } @@ -217,18 +160,3 @@ fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String { }} }}", ty) } - -fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option { - match ty.kind { - ty::Adt(adt_def, substs) if adt_def.is_struct() => { - for field in adt_def.all_fields() { - let f_ty = field.ty(cx.tcx, substs); - if !implements_trait(cx, f_ty, default_trait_id, &[]) { - return None; - } - } - Some(cx.tcx.def_span(adt_def.did)) - }, - _ => None, - } -} diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 2b51b73207585..5f14fe97afefa 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -5,6 +5,7 @@ use rustc_ast::ast::{ use rustc_ast::attr; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::{Ident, SymbolStr}; @@ -131,7 +132,11 @@ struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { fn visit_pat(&mut self, pat: &'tcx Pat) { match pat.kind { - PatKind::Ident(_, ident, _) => self.check_ident(ident), + PatKind::Ident(_, ident, _) => { + if !pat.span.from_expansion() { + self.check_ident(ident); + } + }, PatKind::Struct(_, ref fields, _) => { for field in fields { if !field.is_shorthand { @@ -354,12 +359,20 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { impl EarlyLintPass for NonExpressiveNames { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if in_external_macro(cx.sess, item.span) { + return; + } + if let ItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind { do_check(self, cx, &item.attrs, &sig.decl, blk); } } fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) { + if in_external_macro(cx.sess, item.span) { + return; + } + if let AssocItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind { do_check(self, cx, &item.attrs, &sig.decl, blk); } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 2cdf96714195a..4eac571f96620 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -2,7 +2,7 @@ use crate::utils::ptr::get_spans; use crate::utils::{ - is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg, + is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg, span_lint_and_then, walk_ptrs_hir_ty, }; use if_chain::if_chain; @@ -150,8 +150,16 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_ let fn_def_id = cx.tcx.hir().local_def_id(fn_id); let sig = cx.tcx.fn_sig(fn_def_id); let fn_ty = sig.skip_binder(); + let body = opt_body_id.map(|id| cx.tcx.hir().body(id)); for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() { + // Honor the allow attribute on parameters. See issue 5644. + if let Some(body) = &body { + if is_allowed(cx, PTR_ARG, body.params[idx].hir_id) { + continue; + } + } + if let ty::Ref(_, ty, Mutability::Not) = ty.kind { if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { let mut ty_snippet = None; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 83c6faac04149..1eb26d97ed4d2 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -241,14 +241,14 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { } fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { - fn inside_indexing_expr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool { - matches!( - get_parent_expr(cx, expr), - Some(Expr { + fn inside_indexing_expr<'a>(cx: &'a LateContext<'_, '_>, expr: &Expr<'_>) -> Option<&'a Expr<'a>> { + match get_parent_expr(cx, expr) { + parent_expr @ Some(Expr { kind: ExprKind::Index(..), .. - }) - ) + }) => parent_expr, + _ => None, + } } fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool { @@ -267,18 +267,32 @@ fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); if is_empty_range(limits, ordering); then { - if inside_indexing_expr(cx, expr) { + if let Some(parent_expr) = inside_indexing_expr(cx, expr) { let (reason, outcome) = if ordering == Ordering::Equal { ("empty", "always yield an empty slice") } else { ("reversed", "panic at run-time") }; - span_lint( + span_lint_and_then( cx, REVERSED_EMPTY_RANGES, expr.span, &format!("this range is {} and using it to index a slice will {}", reason, outcome), + |diag| { + if_chain! { + if ordering == Ordering::Equal; + if let ty::Slice(slice_ty) = cx.tables.expr_ty(parent_expr).kind; + then { + diag.span_suggestion( + parent_expr.span, + "if you want an empty slice, use", + format!("[] as &[{}]", slice_ty), + Applicability::MaybeIncorrect + ); + } + } + } ); } else { span_lint_and_then( diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index b12c3c344ef4c..2a81170e49e75 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -2,6 +2,7 @@ use crate::utils::span_lint_and_sugg; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -36,6 +37,9 @@ declare_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if in_external_macro(cx.sess, expr.span) { + return; + } if let ExprKind::Struct(_, ref fields, _) = expr.kind { for field in fields { if field.is_shorthand { diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 2c101220c5d68..8e0cb94317aff 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -161,7 +161,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TriviallyCopyPassByRef { } }, FnKind::Method(..) => (), - _ => return, + FnKind::Closure(..) => return, } // Exclude non-inherent impls diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 95921518986bc..7fa97b2469912 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,14 +1,17 @@ use crate::utils::{ - match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_sugg, + is_type_diagnostic_item, match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, + span_lint_and_help, span_lint_and_sugg, }; +use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { - /// **What it does:** Checks for `Into`/`From`/`IntoIter` calls that useless converts - /// to the same type as caller. + /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls + /// that useless converts to the same type as caller. /// /// **Why is this bad?** Redundant code. /// @@ -26,7 +29,7 @@ declare_clippy_lint! { /// ``` pub USELESS_CONVERSION, complexity, - "calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type" + "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type" } #[derive(Default)] @@ -36,6 +39,7 @@ pub struct UselessConversion { impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]); +#[allow(clippy::too_many_lines)] impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) { if e.span.from_expansion() { @@ -63,12 +67,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { let b = cx.tables.expr_ty(&args[0]); if same_tys(cx, a, b) { let sugg = snippet_with_macro_callsite(cx, args[0].span, "").to_string(); - span_lint_and_sugg( cx, USELESS_CONVERSION, e.span, - "useless conversion", + "useless conversion to the same type", "consider removing `.into()`", sugg, Applicability::MachineApplicable, // snippet @@ -84,22 +87,70 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion", + "useless conversion to the same type", "consider removing `.into_iter()`", sugg, Applicability::MachineApplicable, // snippet ); } } + if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" { + if_chain! { + let a = cx.tables.expr_ty(e); + let b = cx.tables.expr_ty(&args[0]); + if is_type_diagnostic_item(cx, a, sym!(result_type)); + if let ty::Adt(_, substs) = a.kind; + if let Some(a_type) = substs.types().next(); + if same_tys(cx, a_type, b); + + then { + span_lint_and_help( + cx, + USELESS_CONVERSION, + e.span, + "useless conversion to the same type", + None, + "consider removing `.try_into()`", + ); + } + } + } }, ExprKind::Call(ref path, ref args) => { - if let ExprKind::Path(ref qpath) = path.kind { - if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id() { - if match_def_path(cx, def_id, &paths::FROM_FROM) { - let a = cx.tables.expr_ty(e); - let b = cx.tables.expr_ty(&args[0]); - if same_tys(cx, a, b) { + if_chain! { + if args.len() == 1; + if let ExprKind::Path(ref qpath) = path.kind; + if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id(); + let a = cx.tables.expr_ty(e); + let b = cx.tables.expr_ty(&args[0]); + + then { + if_chain! { + if match_def_path(cx, def_id, &paths::TRY_FROM); + if is_type_diagnostic_item(cx, a, sym!(result_type)); + if let ty::Adt(_, substs) = a.kind; + if let Some(a_type) = substs.types().next(); + if same_tys(cx, a_type, b); + + then { + let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); + span_lint_and_help( + cx, + USELESS_CONVERSION, + e.span, + "useless conversion to the same type", + None, + &hint, + ); + } + } + + if_chain! { + if match_def_path(cx, def_id, &paths::FROM_FROM); + if same_tys(cx, a, b); + + then { let sugg = snippet(cx, args[0].span.source_callsite(), "").into_owned(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); @@ -107,7 +158,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion { cx, USELESS_CONVERSION, e.span, - "useless conversion", + "useless conversion to the same type", &sugg_msg, sugg, Applicability::MachineApplicable, // snippet diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 57b9eafd14dbd..9e8e0ff30ec6b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -120,10 +120,12 @@ define_Conf! { "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", - "JavaScript", + "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", - "OpenGL", "OpenSSH", "OpenSSL", "OpenStreetMap", + "OCaml", + "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", + "TensorFlow", "TrueType", "iOS", "macOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 748c11fac64ff..9b672b9ec225b 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -289,21 +289,21 @@ fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}operands:", ind); for op in asm.operands { match op { - hir::InlineAsmOperand::In { expr, .. } => print_expr(cx, expr, indent + 1), + hir::InlineAsmOperand::In { expr, .. } + | hir::InlineAsmOperand::InOut { expr, .. } + | hir::InlineAsmOperand::Const { expr } + | hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1), hir::InlineAsmOperand::Out { expr, .. } => { if let Some(expr) = expr { print_expr(cx, expr, indent + 1); } }, - hir::InlineAsmOperand::InOut { expr, .. } => print_expr(cx, expr, indent + 1), hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { print_expr(cx, in_expr, indent + 1); if let Some(out_expr) = out_expr { print_expr(cx, out_expr, indent + 1); } }, - hir::InlineAsmOperand::Const { expr } => print_expr(cx, expr, indent + 1), - hir::InlineAsmOperand::Sym { expr } => print_expr(cx, expr, indent + 1), } } }, diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index f22473275c466..6c1488664bf00 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -358,7 +358,7 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'_, 'tcx>, hir_id: HirId) -> O pub fn has_drop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.ty_adt_def() { Some(def) => def.has_dtor(cx.tcx), - _ => false, + None => false, } } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index b3ad2ad9d9987..779da7e6bf23c 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -128,8 +128,10 @@ pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned" pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"]; pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"]; pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; +pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"]; pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"]; pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"]; +pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"]; pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"]; pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"]; pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 4ebe2e2852fb4..73758b7eeb7eb 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -530,7 +530,7 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext> { /// Suggest to add an item before another. /// - /// The item should not be indented (expect for inner indentation). + /// The item should not be indented (except for inner indentation). /// /// # Example /// diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 9ad1315c17521..8092be277cca0 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -42,8 +42,10 @@ case), and we don't need type information so it will have an early pass type `cargo dev new_lint --name=foo_functions --pass=early --category=pedantic` (category will default to nursery if not provided). This command will create two files: `tests/ui/foo_functions.rs` and `clippy_lints/src/foo_functions.rs`, -as well as run `cargo dev update_lints` to register the new lint. Next, we'll -open up these files and add our lint! +as well as run `cargo dev update_lints` to register the new lint. For cargo lints, +two project hierarchies (fail/pass) will be created by default under `tests/ui-cargo`. + +Next, we'll open up these files and add our lint! ## Testing @@ -105,6 +107,24 @@ our lint, we need to commit the generated `.stderr` files, too. In general, you should only commit files changed by `tests/ui/update-all-references.sh` for the specific lint you are creating/editing. +### Cargo lints + +For cargo lints, the process of testing differs in that we are interested in +the `Cargo.toml` manifest file. We also need a minimal crate associated +with that manifest. + +If our new lint is named e.g. `foo_categories`, after running `cargo dev new_lint` +we will find by default two new crates, each with its manifest file: + +* `tests/ui-cargo/foo_categories/fail/Cargo.toml`: this file should cause the new lint to raise an error. +* `tests/ui-cargo/foo_categories/pass/Cargo.toml`: this file should not trigger the lint. + +If you need more cases, you can copy one of those crates (under `foo_categories`) and rename it. + +The process of generating the `.stderr` file is the same, and prepending the `TESTNAME` +variable to `cargo uitest` works too, but the script to update the references +is in another path: `tests/ui-cargo/update-all-references.sh`. + ## Rustfix tests If the lint you are working on is making use of structured suggestions, the @@ -445,6 +465,7 @@ Here are some pointers to things you are likely going to need for every lint: * [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro] * [`Span`][span] * [`Applicability`][applicability] +* [Common tools for writing lints](common_tools_writing_lints.md) helps with common operations * [The rustc-dev-guide][rustc-dev-guide] explains a lot of internal compiler concepts * [The nightly rustc docs][nightly_docs] which has been linked to throughout this guide diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md new file mode 100644 index 0000000000000..ed33b37c6bd1b --- /dev/null +++ b/doc/common_tools_writing_lints.md @@ -0,0 +1,152 @@ +# Common tools for writing lints + +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) + - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait) + - [Dealing with macros](#dealing-with-macros) + +Useful Rustc dev guide links: +- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation) +- [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 + +Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for example to answer following questions: + +- which type does this expression correspond to (using its [`TyKind`][TyKind])? +- is it a sized type? +- is it a primitive type? +- does it implement a trait? + +This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct, +that gives you access to the underlying structure [`TyS`][TyS]. + +Example of use: +```rust +impl LateLintPass<'_, '_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + // Get type of `expr` + let ty = cx.tables.expr_ty(expr); + // Match its kind to enter its type + match ty.kind { + ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"), + _ => () + } + } +} +``` + +Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method +to retrieve a type from a pattern. + +Two noticeable items here: +- `cx` is the lint context [`LateContext`][LateContext]. + The two most useful data structures in this context are `tcx` and `tables`, + allowing us to jump to type definitions and other compilation stages such as HIR. +- `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step, + it includes useful information such as types of expressions, ways to resolve methods and so on. + +# Checking if a type implements a specific trait + +There are two ways to do this, depending if the target trait is part of lang items. + +```rust +use crate::utils::{implements_trait, match_trait_method, paths}; + +impl LateLintPass<'_, '_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + // 1. Using expression and Clippy's convenient method + // we use `match_trait_method` function from Clippy's toolbox + if match_trait_method(cx, expr, &paths::INTO) { + // `expr` implements `Into` trait + } + + // 2. Using type context `TyCtxt` + let ty = cx.tables.expr_ty(expr); + if cx.tcx.lang_items() + // we are looking for the `DefId` of `Drop` trait in lang items + .drop_trait() + // then we use it with our type `ty` by calling `implements_trait` from Clippy's utils + .map_or(false, |id| implements_trait(cx, ty, id, &[])) { + // `expr` implements `Drop` trait + } + } +} +``` + +> Prefer using lang items, if the target trait is available there. + +A list of defined paths for Clippy can be found in [paths.rs][paths] + +We access lang items through the type context `tcx`. `tcx` is of type [`TyCtxt`][TyCtxt] and is defined in the `rustc_middle` crate. + +# Dealing with macros + +There are several helpers in Clippy's utils to deal with macros: + +- `in_macro()`: detect if the given span is expanded by a macro + +You may want to use this for example to not start linting in any macro. + +```rust +macro_rules! foo { + ($param:expr) => { + match $param { + "bar" => println!("whatever"), + _ => () + } + }; +} + +foo!("bar"); + +// if we lint the `match` of `foo` call and test its span +assert_eq!(in_macro(match_span), true); +``` + +- `in_external_macro()`: detect if the given span is from an external macro, defined in a foreign crate + +You may want to use it for example to not start linting in macros from other crates + +```rust +#[macro_use] +extern crate a_crate_with_macros; + +// `foo` is defined in `a_crate_with_macros` +foo!("bar"); + +// if we lint the `match` of `foo` call and test its span +assert_eq!(in_external_macro(cx.sess(), match_span), true); +``` + +- `differing_macro_contexts()`: returns true if the two given spans are not from the same context + +```rust +macro_rules! m { + ($a:expr, $b:expr) => { + if $a.is_some() { + $b; + } + } +} + +let x: Option = Some(42); +m!(x, x.unwrap()); + +// These spans are not from the same context +// x.is_some() is from inside the macro +// x.unwrap() is from outside the macro +assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true); +``` + +[TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[TypeckTables]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html +[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html#method.expr_ty +[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html +[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckTables.html#method.pat_ty +[paths]: ../clippy_lints/src/utils/paths.rs diff --git a/rustc_tools_util/LICENSE-APACHE b/rustc_tools_util/LICENSE-APACHE new file mode 120000 index 0000000000000..965b606f331b5 --- /dev/null +++ b/rustc_tools_util/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/rustc_tools_util/LICENSE-MIT b/rustc_tools_util/LICENSE-MIT new file mode 120000 index 0000000000000..76219eb72e852 --- /dev/null +++ b/rustc_tools_util/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/setup-toolchain.sh b/setup-toolchain.sh index 6038ed697f91e..191ea4315a6b5 100755 --- a/setup-toolchain.sh +++ b/setup-toolchain.sh @@ -32,5 +32,5 @@ else TOOLCHAIN=() fi -rustup-toolchain-install-master -f -n master "${TOOLCHAIN[@]}" -c rustc-dev -- "$RUST_COMMIT" +rustup-toolchain-install-master -f -n master "${TOOLCHAIN[@]}" -c rustc-dev -c llvm-tools -- "$RUST_COMMIT" rustup override set master diff --git a/src/driver.rs b/src/driver.rs index d3a7e24937f95..70c47b426825e 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -79,7 +79,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { let conf = clippy_lints::read_conf(&[], &sess); clippy_lints::register_plugins(&mut lint_store, &sess, &conf); - clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf); + clippy_lints::register_pre_expansion_lints(&mut lint_store); clippy_lints::register_renamed(&mut lint_store); })); diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 9457a64f9c6b9..f63301c7db0a6 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1195,11 +1195,18 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "match_wild_err_arm", - group: "style", + group: "pedantic", desc: "a `match` with `Err(_)` arm and take drastic actions", deprecation: None, module: "matches", }, + Lint { + name: "match_wildcard_for_single_variants", + group: "pedantic", + desc: "a wildcard enum match for a single variant", + deprecation: None, + module: "matches", + }, Lint { name: "maybe_infinite_iter", group: "pedantic", @@ -2414,7 +2421,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "useless_conversion", group: "complexity", - desc: "calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type", + desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type", deprecation: None, module: "useless_conversion", }, diff --git a/tests/compile-test.rs b/tests/compile-test.rs index de2cf6d7873f8..2758b9a7e7604 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -38,13 +38,13 @@ fn clippy_driver_path() -> PathBuf { // as what we manually pass to `cargo` invocation fn third_party_crates() -> String { use std::collections::HashMap; - static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints"]; + static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints", "syn", "quote"]; let dep_dir = cargo::TARGET_LIB.join("deps"); let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len()); for entry in fs::read_dir(dep_dir).unwrap() { let path = match entry { Ok(entry) => entry.path(), - _ => continue, + Err(_) => continue, }; if let Some(name) = path.file_name().and_then(OsStr::to_str) { for dep in CRATES { @@ -101,54 +101,133 @@ fn run_mode(cfg: &mut compiletest::Config) { compiletest::run_tests(&cfg); } -#[allow(clippy::identity_conversion)] -fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec) -> Result { - let mut result = true; - let opts = compiletest::test_opts(config); - for dir in fs::read_dir(&config.src_base)? { - let dir = dir?; - if !dir.file_type()?.is_dir() { - continue; - } - let dir_path = dir.path(); - set_var("CARGO_MANIFEST_DIR", &dir_path); - for file in fs::read_dir(&dir_path)? { - let file = file?; - let file_path = file.path(); - if file.file_type()?.is_dir() { +fn run_ui_toml(config: &mut compiletest::Config) { + fn run_tests(config: &compiletest::Config, mut tests: Vec) -> Result { + let mut result = true; + let opts = compiletest::test_opts(config); + for dir in fs::read_dir(&config.src_base)? { + let dir = dir?; + if !dir.file_type()?.is_dir() { continue; } - if file_path.extension() != Some(OsStr::new("rs")) { - continue; + let dir_path = dir.path(); + set_var("CARGO_MANIFEST_DIR", &dir_path); + for file in fs::read_dir(&dir_path)? { + let file = file?; + let file_path = file.path(); + if file.file_type()?.is_dir() { + continue; + } + if file_path.extension() != Some(OsStr::new("rs")) { + continue; + } + let paths = compiletest::common::TestPaths { + file: file_path, + base: config.src_base.clone(), + relative_dir: dir_path.file_name().unwrap().into(), + }; + let test_name = compiletest::make_test_name(&config, &paths); + let index = tests + .iter() + .position(|test| test.desc.name == test_name) + .expect("The test should be in there"); + result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?; } - let paths = compiletest::common::TestPaths { - file: file_path, - base: config.src_base.clone(), - relative_dir: dir_path.file_name().unwrap().into(), - }; - let test_name = compiletest::make_test_name(&config, &paths); - let index = tests - .iter() - .position(|test| test.desc.name == test_name) - .expect("The test should be in there"); - result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?; } + Ok(result) } - Ok(result) -} -fn run_ui_toml(config: &mut compiletest::Config) { config.mode = TestMode::Ui; config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap(); let tests = compiletest::make_tests(&config); - let res = run_ui_toml_tests(&config, tests); + let res = run_tests(&config, tests); + match res { + Ok(true) => {}, + Ok(false) => panic!("Some tests failed"), + Err(e) => { + panic!("I/O failure during tests: {:?}", e); + }, + } +} + +fn run_ui_cargo(config: &mut compiletest::Config) { + fn run_tests( + config: &compiletest::Config, + filter: &Option, + mut tests: Vec, + ) -> Result { + let mut result = true; + let opts = compiletest::test_opts(config); + + for dir in fs::read_dir(&config.src_base)? { + let dir = dir?; + if !dir.file_type()?.is_dir() { + continue; + } + + // Use the filter if provided + let dir_path = dir.path(); + match &filter { + Some(name) if !dir_path.ends_with(name) => continue, + _ => {}, + } + + for case in fs::read_dir(&dir_path)? { + let case = case?; + if !case.file_type()?.is_dir() { + continue; + } + + let src_path = case.path().join("src"); + env::set_current_dir(&src_path)?; + + for file in fs::read_dir(&src_path)? { + let file = file?; + if file.file_type()?.is_dir() { + continue; + } + + // Search for the main file to avoid running a test for each file in the project + let file_path = file.path(); + match file_path.file_name().and_then(OsStr::to_str) { + Some("main.rs") => {}, + _ => continue, + } + + let paths = compiletest::common::TestPaths { + file: file_path, + base: config.src_base.clone(), + relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(), + }; + let test_name = compiletest::make_test_name(&config, &paths); + let index = tests + .iter() + .position(|test| test.desc.name == test_name) + .expect("The test should be in there"); + result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?; + } + } + } + Ok(result) + } + + config.mode = TestMode::Ui; + config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap(); + + let tests = compiletest::make_tests(&config); + + let current_dir = env::current_dir().unwrap(); + let filter = env::var("TESTNAME").ok(); + let res = run_tests(&config, &filter, tests); + env::set_current_dir(current_dir).unwrap(); + match res { Ok(true) => {}, Ok(false) => panic!("Some tests failed"), Err(e) => { - println!("I/O failure during tests: {:?}", e); + panic!("I/O failure during tests: {:?}", e); }, } } @@ -165,4 +244,5 @@ fn compile_test() { let mut config = default_config(); run_mode(&mut config); run_ui_toml(&mut config); + run_ui_cargo(&mut config); } diff --git a/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml new file mode 100644 index 0000000000000..c64adcf7c0131 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = false diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr new file mode 100644 index 0000000000000..c8ae6c820df9d --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr @@ -0,0 +1,18 @@ +error: package `cargo_common_metadata` is missing `package.authors` metadata + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + +error: package `cargo_common_metadata` is missing `package.description` metadata + +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata + +error: package `cargo_common_metadata` is missing `package.repository` metadata + +error: package `cargo_common_metadata` is missing `package.readme` metadata + +error: package `cargo_common_metadata` is missing `package.keywords` metadata + +error: package `cargo_common_metadata` is missing `package.categories` metadata + +error: aborting due to 7 previous errors + diff --git a/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml new file mode 100644 index 0000000000000..c8233f328bb05 --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = false +authors = ["Random person from the Internet "] +description = "A test package for the cargo_common_metadata lint" +repository = "https://github.com/someone/cargo_common_metadata" +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["metadata", "lint", "clippy"] +categories = ["development-tools::testing"] diff --git a/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml new file mode 100644 index 0000000000000..72731fbc75d00 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml @@ -0,0 +1,17 @@ +# Should not lint for dev or build dependencies. See issue 5041. + +[package] +name = "multiple_crate_versions" +version = "0.1.0" +publish = false + +# One of the versions of winapi is only a dev dependency: allowed +[dependencies] +ctrlc = "=3.1.0" +[dev-dependencies] +ansi_term = "=0.11.0" + +# Both versions of winapi are a build dependency: allowed +[build-dependencies] +ctrlc = "=3.1.0" +ansi_term = "=0.11.0" diff --git a/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs new file mode 100644 index 0000000000000..1b2d3ec9459f9 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=multiple_crate_versions +#![warn(clippy::multiple_crate_versions)] + +fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml new file mode 100644 index 0000000000000..3a94b723f3fdb --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "multiple_crate_versions" +version = "0.1.0" +publish = false + +[dependencies] +ctrlc = "=3.1.0" +ansi_term = "=0.11.0" diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs new file mode 100644 index 0000000000000..1b2d3ec9459f9 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=multiple_crate_versions +#![warn(clippy::multiple_crate_versions)] + +fn main() {} diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr new file mode 100644 index 0000000000000..4f668599be950 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr @@ -0,0 +1,6 @@ +error: multiple versions for dependency `winapi`: 0.2.8, 0.3.8 + | + = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml b/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml new file mode 100644 index 0000000000000..a9b06420b333d --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = false + +[dependencies] +regex = "1.3.7" +serde = "1.0.110" diff --git a/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs new file mode 100644 index 0000000000000..1b2d3ec9459f9 --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=multiple_crate_versions +#![warn(clippy::multiple_crate_versions)] + +fn main() {} diff --git a/tests/ui-cargo/update-all-references.sh b/tests/ui-cargo/update-all-references.sh new file mode 100755 index 0000000000000..7028b251ea030 --- /dev/null +++ b/tests/ui-cargo/update-all-references.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# A script to update the references for all tests. The idea is that +# you do a run, which will generate files in the build directory +# containing the (normalized) actual output of the compiler. You then +# run this script, which will copy those files over. If you find +# yourself manually editing a foo.stderr file, you're doing it wrong. +# +# See all `update-references.sh`, if you just want to update a single test. + +if [[ "$1" == "--help" || "$1" == "-h" ]]; then + echo "usage: $0" +fi + +BUILD_DIR=$PWD/target/debug/test_build_base +MY_DIR=$(dirname "$0") +cd "$MY_DIR" || exit +find . -name '*.rs' -exec ./update-references.sh "$BUILD_DIR" {} + diff --git a/tests/ui-cargo/update-references.sh b/tests/ui-cargo/update-references.sh new file mode 100755 index 0000000000000..50d42678734e9 --- /dev/null +++ b/tests/ui-cargo/update-references.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# A script to update the references for particular tests. The idea is +# that you do a run, which will generate files in the build directory +# containing the (normalized) actual output of the compiler. This +# script will then copy that output and replace the "expected output" +# files. You can then commit the changes. +# +# If you find yourself manually editing a foo.stderr file, you're +# doing it wrong. + +if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then + echo "usage: $0 " + echo "" + echo "For example:" + echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" +fi + +MYDIR=$(dirname "$0") + +BUILD_DIR="$1" +shift + +while [[ "$1" != "" ]]; do + STDERR_NAME="${1/%.rs/.stderr}" + STDOUT_NAME="${1/%.rs/.stdout}" + shift + if [[ -f "$BUILD_DIR"/"$STDOUT_NAME" ]] && \ + ! (cmp -s -- "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME"); then + echo updating "$MYDIR"/"$STDOUT_NAME" + cp "$BUILD_DIR"/"$STDOUT_NAME" "$MYDIR"/"$STDOUT_NAME" + fi + if [[ -f "$BUILD_DIR"/"$STDERR_NAME" ]] && \ + ! (cmp -s -- "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME"); then + echo updating "$MYDIR"/"$STDERR_NAME" + cp "$BUILD_DIR"/"$STDERR_NAME" "$MYDIR"/"$STDERR_NAME" + fi +done diff --git a/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml b/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml new file mode 100644 index 0000000000000..fd2a341485683 --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "wildcard_dependencies" +version = "0.1.0" +publish = false + +[dependencies] +regex = "*" diff --git a/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs new file mode 100644 index 0000000000000..581babfeacbff --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=wildcard_dependencies +#![warn(clippy::wildcard_dependencies)] + +fn main() {} diff --git a/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr b/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr new file mode 100644 index 0000000000000..9e65d2f99420a --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr @@ -0,0 +1,6 @@ +error: wildcard dependency for `regex` + | + = note: `-D clippy::wildcard-dependencies` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml b/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml new file mode 100644 index 0000000000000..38cb139146e05 --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "wildcard_dependencies" +version = "0.1.0" +publish = false + +[dependencies] +regex = "1" diff --git a/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs new file mode 100644 index 0000000000000..581babfeacbff --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=wildcard_dependencies +#![warn(clippy::wildcard_dependencies)] + +fn main() {} diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs new file mode 100644 index 0000000000000..e6626d57a7722 --- /dev/null +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -0,0 +1,37 @@ +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(repr128, proc_macro_hygiene, proc_macro_quote)] +#![allow(clippy::useless_conversion)] + +extern crate proc_macro; +extern crate quote; +extern crate syn; + +use proc_macro::TokenStream; +use quote::{quote, quote_spanned}; +use syn::parse_macro_input; +use syn::{parse_quote, ItemTrait, TraitItem}; + +#[proc_macro_attribute] +pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream { + let mut item = parse_macro_input!(input as ItemTrait); + for inner in &mut item.items { + if let TraitItem::Method(method) = inner { + let sig = &method.sig; + let block = &mut method.default; + if let Some(block) = block { + let brace = block.brace_token; + + let my_block = quote_spanned!( brace.span => { + // Should not trigger `empty_line_after_outer_attr` + #[crate_type = "lib"] + #sig #block + Vec::new() + }); + *block = parse_quote!(#my_block); + } + } + } + TokenStream::from(quote!(#item)) +} diff --git a/tests/ui/cognitive_complexity.rs b/tests/ui/cognitive_complexity.rs index 1d3fe405521cd..912e6788afddc 100644 --- a/tests/ui/cognitive_complexity.rs +++ b/tests/ui/cognitive_complexity.rs @@ -1,6 +1,6 @@ #![allow(clippy::all)] #![warn(clippy::cognitive_complexity)] -#![allow(unused)] +#![allow(unused, unused_crate_dependencies)] #[rustfmt::skip] fn main() { diff --git a/tests/ui/cognitive_complexity_attr_used.rs b/tests/ui/cognitive_complexity_attr_used.rs index 403eff566ed6d..771a26fc9a86d 100644 --- a/tests/ui/cognitive_complexity_attr_used.rs +++ b/tests/ui/cognitive_complexity_attr_used.rs @@ -1,5 +1,5 @@ -#![warn(clippy::cognitive_complexity)] -#![warn(unused)] +#![warn(unused, clippy::cognitive_complexity)] +#![allow(unused_crate_dependencies)] fn main() { kaboom(); diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 5343dff9da1db..3e92bca986ab5 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -1,8 +1,12 @@ +// aux-build:proc_macro_attr.rs #![warn(clippy::empty_line_after_outer_attr)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] #![rustfmt::skip] +#[macro_use] +extern crate proc_macro_attr; + // This should produce a warning #[crate_type = "lib"] @@ -93,4 +97,17 @@ pub struct S; /* test */ pub struct T; -fn main() { } +// This should not produce a warning +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec { + let _i = ""; + + + + vec![] + } +} + +fn main() {} diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr index d8c9786541f0b..bf753a732f000 100644 --- a/tests/ui/empty_line_after_outer_attribute.stderr +++ b/tests/ui/empty_line_after_outer_attribute.stderr @@ -1,5 +1,5 @@ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:7:1 + --> $DIR/empty_line_after_outer_attribute.rs:11:1 | LL | / #[crate_type = "lib"] LL | | @@ -10,7 +10,7 @@ LL | | fn with_one_newline_and_comment() { assert!(true) } = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:19:1 + --> $DIR/empty_line_after_outer_attribute.rs:23:1 | LL | / #[crate_type = "lib"] LL | | @@ -18,7 +18,7 @@ LL | | fn with_one_newline() { assert!(true) } | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:24:1 + --> $DIR/empty_line_after_outer_attribute.rs:28:1 | LL | / #[crate_type = "lib"] LL | | @@ -27,7 +27,7 @@ LL | | fn with_two_newlines() { assert!(true) } | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:31:1 + --> $DIR/empty_line_after_outer_attribute.rs:35:1 | LL | / #[crate_type = "lib"] LL | | @@ -35,7 +35,7 @@ LL | | enum Baz { | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:39:1 + --> $DIR/empty_line_after_outer_attribute.rs:43:1 | LL | / #[crate_type = "lib"] LL | | @@ -43,7 +43,7 @@ LL | | struct Foo { | |_ error: Found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:47:1 + --> $DIR/empty_line_after_outer_attribute.rs:51:1 | LL | / #[crate_type = "lib"] LL | | diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr index d1863701bfe7c..b59dbb3e76c64 100644 --- a/tests/ui/future_not_send.stderr +++ b/tests/ui/future_not_send.stderr @@ -47,17 +47,32 @@ error: future cannot be sent between threads safely --> $DIR/future_not_send.rs:20:63 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - | ^^^^ + | ^^^^ future returned by `private_future2` is not `Send` | +note: captured value is not `Send` + --> $DIR/future_not_send.rs:20:26 + | +LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { + | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` +note: captured value is not `Send` + --> $DIR/future_not_send.rs:20:40 + | +LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { + | ^^^^ has type `&std::cell::Cell` which is not `Send` = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely --> $DIR/future_not_send.rs:24:43 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} - | ^ + | ^ future returned by `public_future2` is not `Send` | +note: captured value is not `Send` + --> $DIR/future_not_send.rs:24:29 + | +LL | pub async fn public_future2(rc: Rc<[u8]>) {} + | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely @@ -117,8 +132,13 @@ error: future cannot be sent between threads safely --> $DIR/future_not_send.rs:66:34 | LL | async fn unclear_future(t: T) {} - | ^ + | ^ future returned by `unclear_future` is not `Send` | +note: captured value is not `Send` + --> $DIR/future_not_send.rs:66:28 + | +LL | async fn unclear_future(t: T) {} + | ^ has type `T` which is not `Send` = note: `T` doesn't implement `std::marker::Send` error: aborting due to 8 previous errors diff --git a/tests/ui/match_wild_err_arm.stderr b/tests/ui/match_wild_err_arm.stderr index 20d4c933418b7..6a2a02987dea7 100644 --- a/tests/ui/match_wild_err_arm.stderr +++ b/tests/ui/match_wild_err_arm.stderr @@ -5,7 +5,7 @@ LL | Err(_) => panic!("err"), | ^^^^^^ | = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` - = note: match each error separately or use the error output + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:17:9 @@ -13,7 +13,7 @@ error: `Err(_)` matches all errors LL | Err(_) => panic!(), | ^^^^^^ | - = note: match each error separately or use the error output + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:23:9 @@ -21,7 +21,7 @@ error: `Err(_)` matches all errors LL | Err(_) => { | ^^^^^^ | - = note: match each error separately or use the error output + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: `Err(_e)` matches all errors --> $DIR/match_wild_err_arm.rs:31:9 @@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors LL | Err(_e) => panic!(), | ^^^^^^^ | - = note: match each error separately or use the error output + = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable error: aborting due to 4 previous errors diff --git a/tests/ui/match_wildcard_for_single_variants.fixed b/tests/ui/match_wildcard_for_single_variants.fixed new file mode 100644 index 0000000000000..519200977a798 --- /dev/null +++ b/tests/ui/match_wildcard_for_single_variants.fixed @@ -0,0 +1,59 @@ +// run-rustfix + +#![warn(clippy::match_wildcard_for_single_variants)] +#![allow(dead_code)] + +enum Foo { + A, + B, + C, +} + +enum Color { + Red, + Green, + Blue, + Rgb(u8, u8, u8), +} + +fn main() { + let f = Foo::A; + match f { + Foo::A => {}, + Foo::B => {}, + Foo::C => {}, + } + + let color = Color::Red; + + // check exhaustive bindings + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(_r, _g, _b) => {}, + Color::Blue => {}, + } + + // check exhaustive wild + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(..) => {}, + Color::Blue => {}, + } + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(_, _, _) => {}, + Color::Blue => {}, + } + + // shouldn't lint as there is one missing variant + // and one that isn't exhaustively covered + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(255, _, _) => {}, + _ => {}, + } +} diff --git a/tests/ui/match_wildcard_for_single_variants.rs b/tests/ui/match_wildcard_for_single_variants.rs new file mode 100644 index 0000000000000..1df917e085c71 --- /dev/null +++ b/tests/ui/match_wildcard_for_single_variants.rs @@ -0,0 +1,59 @@ +// run-rustfix + +#![warn(clippy::match_wildcard_for_single_variants)] +#![allow(dead_code)] + +enum Foo { + A, + B, + C, +} + +enum Color { + Red, + Green, + Blue, + Rgb(u8, u8, u8), +} + +fn main() { + let f = Foo::A; + match f { + Foo::A => {}, + Foo::B => {}, + _ => {}, + } + + let color = Color::Red; + + // check exhaustive bindings + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(_r, _g, _b) => {}, + _ => {}, + } + + // check exhaustive wild + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(..) => {}, + _ => {}, + } + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(_, _, _) => {}, + _ => {}, + } + + // shouldn't lint as there is one missing variant + // and one that isn't exhaustively covered + match color { + Color::Red => {}, + Color::Green => {}, + Color::Rgb(255, _, _) => {}, + _ => {}, + } +} diff --git a/tests/ui/match_wildcard_for_single_variants.stderr b/tests/ui/match_wildcard_for_single_variants.stderr new file mode 100644 index 0000000000000..82790aa9e80bb --- /dev/null +++ b/tests/ui/match_wildcard_for_single_variants.stderr @@ -0,0 +1,28 @@ +error: wildcard match will miss any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:24:9 + | +LL | _ => {}, + | ^ help: try this: `Foo::C` + | + = note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings` + +error: wildcard match will miss any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:34:9 + | +LL | _ => {}, + | ^ help: try this: `Color::Blue` + +error: wildcard match will miss any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:42:9 + | +LL | _ => {}, + | ^ help: try this: `Color::Blue` + +error: wildcard match will miss any future added variants + --> $DIR/match_wildcard_for_single_variants.rs:48:9 + | +LL | _ => {}, + | ^ help: try this: `Color::Blue` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index 781ea7bb15283..3b6041823d878 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -148,4 +148,15 @@ impl AllowDerive { } } +pub struct NewNotEqualToDerive { + foo: i32, +} + +impl NewNotEqualToDerive { + // This `new` implementation is not equal to a derived `Default`, so do not suggest deriving. + pub fn new() -> Self { + NewNotEqualToDerive { foo: 1 } + } +} + fn main() {} diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 5e485d40663f3..e529e441eb735 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -1,4 +1,4 @@ -error: you should consider deriving a `Default` implementation for `Foo` +error: you should consider adding a `Default` implementation for `Foo` --> $DIR/new_without_default.rs:8:5 | LL | / pub fn new() -> Foo { @@ -9,10 +9,14 @@ LL | | } = note: `-D clippy::new-without-default` implied by `-D warnings` help: try this | -LL | #[derive(Default)] +LL | impl Default for Foo { +LL | fn default() -> Self { +LL | Self::new() +LL | } +LL | } | -error: you should consider deriving a `Default` implementation for `Bar` +error: you should consider adding a `Default` implementation for `Bar` --> $DIR/new_without_default.rs:16:5 | LL | / pub fn new() -> Self { @@ -22,7 +26,11 @@ LL | | } | help: try this | -LL | #[derive(Default)] +LL | impl Default for Bar { +LL | fn default() -> Self { +LL | Self::new() +LL | } +LL | } | error: you should consider adding a `Default` implementation for `LtKo<'c>` @@ -42,5 +50,22 @@ LL | } LL | } | -error: aborting due to 3 previous errors +error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` + --> $DIR/new_without_default.rs:157:5 + | +LL | / pub fn new() -> Self { +LL | | NewNotEqualToDerive { foo: 1 } +LL | | } + | |_____^ + | +help: try this + | +LL | impl Default for NewNotEqualToDerive { +LL | fn default() -> Self { +LL | Self::new() +LL | } +LL | } + | + +error: aborting due to 4 previous errors diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index 904c50e14039a..a2617a13ecace 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -60,3 +60,28 @@ fn main() { // The lint allows this let expr = Some(Some(true)); } + +extern crate serde; +mod issue_4298 { + use serde::{Deserialize, Deserializer, Serialize}; + use std::borrow::Cow; + + #[derive(Serialize, Deserialize)] + struct Foo<'a> { + #[serde(deserialize_with = "func")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + #[serde(borrow)] + // FIXME: should not lint here + #[allow(clippy::option_option)] + foo: Option>>, + } + + #[allow(clippy::option_option)] + fn func<'a, D>(_: D) -> Result>>, D::Error> + where + D: Deserializer<'a>, + { + Ok(Some(Some(Cow::Borrowed("hi")))) + } +} diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 79db186d7ea77..0cd4c96eb4f9a 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -58,5 +58,11 @@ error: consider using `Option` instead of `Option>` or a custom enu LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases + --> $DIR/option_option.rs:77:14 + | +LL | foo: Option>>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 8ea03fe42616c..7bb08797ef396 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -95,6 +95,15 @@ fn test_or_with_ctors() { let b = "b".to_string(); let _ = Some(Bar("a".to_string(), Duration::from_secs(1))) .or(Some(Bar(b, Duration::from_secs(2)))); + + let vec = vec!["foo"]; + let _ = opt.ok_or(vec.len()); + + let array = ["foo"]; + let _ = opt.ok_or(array.len()); + + let slice = &["foo"][..]; + let _ = opt.ok_or(slice.len()); } // Issue 4514 - early return diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 7599b945a9137..522f31b72d01f 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -95,6 +95,15 @@ fn test_or_with_ctors() { let b = "b".to_string(); let _ = Some(Bar("a".to_string(), Duration::from_secs(1))) .or(Some(Bar(b, Duration::from_secs(2)))); + + let vec = vec!["foo"]; + let _ = opt.ok_or(vec.len()); + + let array = ["foo"]; + let _ = opt.ok_or(array.len()); + + let slice = &["foo"][..]; + let _ = opt.ok_or(slice.len()); } // Issue 4514 - early return diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 30f39e9b06398..541225e635102 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -71,7 +71,6 @@ fn false_positive_capacity_too(x: &String) -> String { #[allow(dead_code)] fn test_cow_with_ref(c: &Cow<[i32]>) {} -#[allow(dead_code)] fn test_cow(c: Cow<[i32]>) { let _c = c; } @@ -84,3 +83,34 @@ trait Foo2 { impl Foo2 for String { fn do_string(&self) {} } + +// Check that the allow attribute on parameters is honored +mod issue_5644 { + use std::borrow::Cow; + + fn allowed( + #[allow(clippy::ptr_arg)] _v: &Vec, + #[allow(clippy::ptr_arg)] _s: &String, + #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + ) { + } + + struct S {} + impl S { + fn allowed( + #[allow(clippy::ptr_arg)] _v: &Vec, + #[allow(clippy::ptr_arg)] _s: &String, + #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + ) { + } + } + + trait T { + fn allowed( + #[allow(clippy::ptr_arg)] _v: &Vec, + #[allow(clippy::ptr_arg)] _s: &String, + #[allow(clippy::ptr_arg)] _c: &Cow<[i32]>, + ) { + } + } +} diff --git a/tests/ui/ptr_offset_with_cast.fixed b/tests/ui/ptr_offset_with_cast.fixed index ebdd6c4003d19..718e391e8bf69 100644 --- a/tests/ui/ptr_offset_with_cast.fixed +++ b/tests/ui/ptr_offset_with_cast.fixed @@ -9,12 +9,12 @@ fn main() { let offset_isize = 1_isize; unsafe { - ptr.add(offset_usize); - ptr.offset(offset_isize as isize); - ptr.offset(offset_u8 as isize); + let _ = ptr.add(offset_usize); + let _ = ptr.offset(offset_isize as isize); + let _ = ptr.offset(offset_u8 as isize); - ptr.wrapping_add(offset_usize); - ptr.wrapping_offset(offset_isize as isize); - ptr.wrapping_offset(offset_u8 as isize); + let _ = ptr.wrapping_add(offset_usize); + let _ = ptr.wrapping_offset(offset_isize as isize); + let _ = ptr.wrapping_offset(offset_u8 as isize); } } diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs index 3416c4b727a53..f613742c741ef 100644 --- a/tests/ui/ptr_offset_with_cast.rs +++ b/tests/ui/ptr_offset_with_cast.rs @@ -9,12 +9,12 @@ fn main() { let offset_isize = 1_isize; unsafe { - ptr.offset(offset_usize as isize); - ptr.offset(offset_isize as isize); - ptr.offset(offset_u8 as isize); + let _ = ptr.offset(offset_usize as isize); + let _ = ptr.offset(offset_isize as isize); + let _ = ptr.offset(offset_u8 as isize); - ptr.wrapping_offset(offset_usize as isize); - ptr.wrapping_offset(offset_isize as isize); - ptr.wrapping_offset(offset_u8 as isize); + let _ = ptr.wrapping_offset(offset_usize as isize); + let _ = ptr.wrapping_offset(offset_isize as isize); + let _ = ptr.wrapping_offset(offset_u8 as isize); } } diff --git a/tests/ui/ptr_offset_with_cast.stderr b/tests/ui/ptr_offset_with_cast.stderr index b5c7a03e2775e..fd45224ca067f 100644 --- a/tests/ui/ptr_offset_with_cast.stderr +++ b/tests/ui/ptr_offset_with_cast.stderr @@ -1,16 +1,16 @@ error: use of `offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:12:9 + --> $DIR/ptr_offset_with_cast.rs:12:17 | -LL | ptr.offset(offset_usize as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)` +LL | let _ = ptr.offset(offset_usize as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)` | = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings` error: use of `wrapping_offset` with a `usize` casted to an `isize` - --> $DIR/ptr_offset_with_cast.rs:16:9 + --> $DIR/ptr_offset_with_cast.rs:16:17 | -LL | ptr.wrapping_offset(offset_usize as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)` +LL | let _ = ptr.wrapping_offset(offset_usize as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)` error: aborting due to 2 previous errors diff --git a/tests/ui/reversed_empty_ranges_fixable.fixed b/tests/ui/reversed_empty_ranges_fixable.fixed index ee2cbc3cf540e..332c0427ef65a 100644 --- a/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/tests/ui/reversed_empty_ranges_fixable.fixed @@ -4,18 +4,23 @@ const ANSWER: i32 = 42; fn main() { + let arr = [1, 2, 3, 4, 5]; + + // These should be linted: + (21..=42).rev().for_each(|x| println!("{}", x)); let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::>(); for _ in (-42..=-21).rev() {} for _ in (21u32..42u32).rev() {} + let _ = &[] as &[i32]; + // These should be ignored as they are not empty ranges: (21..=42).for_each(|x| println!("{}", x)); (21..42).for_each(|x| println!("{}", x)); - let arr = [1, 2, 3, 4, 5]; let _ = &arr[1..=3]; let _ = &arr[1..3]; diff --git a/tests/ui/reversed_empty_ranges_fixable.rs b/tests/ui/reversed_empty_ranges_fixable.rs index 6ed5ca6daa0e8..901ec8bcc09f4 100644 --- a/tests/ui/reversed_empty_ranges_fixable.rs +++ b/tests/ui/reversed_empty_ranges_fixable.rs @@ -4,18 +4,23 @@ const ANSWER: i32 = 42; fn main() { + let arr = [1, 2, 3, 4, 5]; + + // These should be linted: + (42..=21).for_each(|x| println!("{}", x)); let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); for _ in -21..=-42 {} for _ in 42u32..21u32 {} + let _ = &arr[3..3]; + // These should be ignored as they are not empty ranges: (21..=42).for_each(|x| println!("{}", x)); (21..42).for_each(|x| println!("{}", x)); - let arr = [1, 2, 3, 4, 5]; let _ = &arr[1..=3]; let _ = &arr[1..3]; diff --git a/tests/ui/reversed_empty_ranges_fixable.stderr b/tests/ui/reversed_empty_ranges_fixable.stderr index 97933b8ff8515..9a646fd99398d 100644 --- a/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/tests/ui/reversed_empty_ranges_fixable.stderr @@ -1,5 +1,5 @@ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:7:5 + --> $DIR/reversed_empty_ranges_fixable.rs:11:5 | LL | (42..=21).for_each(|x| println!("{}", x)); | ^^^^^^^^^ @@ -11,7 +11,7 @@ LL | (21..=42).rev().for_each(|x| println!("{}", x)); | ^^^^^^^^^^^^^^^ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:8:13 + --> $DIR/reversed_empty_ranges_fixable.rs:12:13 | LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect:: $DIR/reversed_empty_ranges_fixable.rs:10:14 + --> $DIR/reversed_empty_ranges_fixable.rs:14:14 | LL | for _ in -21..=-42 {} | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | for _ in (-42..=-21).rev() {} | ^^^^^^^^^^^^^^^^^ error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_fixable.rs:11:14 + --> $DIR/reversed_empty_ranges_fixable.rs:15:14 | LL | for _ in 42u32..21u32 {} | ^^^^^^^^^^^^ @@ -43,5 +43,11 @@ help: consider using the following if you are attempting to iterate over this ra LL | for _ in (21u32..42u32).rev() {} | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: this range is empty and using it to index a slice will always yield an empty slice + --> $DIR/reversed_empty_ranges_fixable.rs:17:18 + | +LL | let _ = &arr[3..3]; + | ----^^^^- help: if you want an empty slice, use: `[] as &[i32]` + +error: aborting due to 5 previous errors diff --git a/tests/ui/reversed_empty_ranges_unfixable.rs b/tests/ui/reversed_empty_ranges_unfixable.rs index c9ca4c4766831..561a35625f02e 100644 --- a/tests/ui/reversed_empty_ranges_unfixable.rs +++ b/tests/ui/reversed_empty_ranges_unfixable.rs @@ -9,7 +9,6 @@ fn main() { let arr = [1, 2, 3, 4, 5]; let _ = &arr[3usize..=1usize]; let _ = &arr[SOME_NUM..1]; - let _ = &arr[3..3]; for _ in ANSWER..ANSWER {} } diff --git a/tests/ui/reversed_empty_ranges_unfixable.stderr b/tests/ui/reversed_empty_ranges_unfixable.stderr index 12e5483ecdfff..240188cbb46cb 100644 --- a/tests/ui/reversed_empty_ranges_unfixable.stderr +++ b/tests/ui/reversed_empty_ranges_unfixable.stderr @@ -18,17 +18,11 @@ error: this range is reversed and using it to index a slice will panic at run-ti LL | let _ = &arr[SOME_NUM..1]; | ^^^^^^^^^^^ -error: this range is empty and using it to index a slice will always yield an empty slice - --> $DIR/reversed_empty_ranges_unfixable.rs:12:18 - | -LL | let _ = &arr[3..3]; - | ^^^^ - error: this range is empty so it will yield no values - --> $DIR/reversed_empty_ranges_unfixable.rs:14:14 + --> $DIR/reversed_empty_ranges_unfixable.rs:13:14 | LL | for _ in ANSWER..ANSWER {} | ^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 7df3507edfd9e..84ec53702788c 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,4 +1,4 @@ -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:6:13 | LL | let _ = T::from(val); @@ -10,55 +10,55 @@ note: the lint level is defined here LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:7:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:19:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:51:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:52:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:53:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:54:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:55:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:56:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` -error: useless conversion +error: useless conversion to the same type --> $DIR/useless_conversion.rs:57:21 | LL | let _: String = format!("Hello {}", "world").into(); diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs new file mode 100644 index 0000000000000..3787ea991445c --- /dev/null +++ b/tests/ui/useless_conversion_try.rs @@ -0,0 +1,42 @@ +#![deny(clippy::useless_conversion)] + +use std::convert::{TryFrom, TryInto}; + +fn test_generic(val: T) -> T { + let _ = T::try_from(val).unwrap(); + val.try_into().unwrap() +} + +fn test_generic2 + Into, U: From>(val: T) { + // ok + let _: i32 = val.try_into().unwrap(); + let _: U = val.try_into().unwrap(); + let _ = U::try_from(val).unwrap(); +} + +fn main() { + test_generic(10i32); + test_generic2::(10i32); + + let _: String = "foo".try_into().unwrap(); + let _: String = TryFrom::try_from("foo").unwrap(); + let _ = String::try_from("foo").unwrap(); + #[allow(clippy::useless_conversion)] + { + let _ = String::try_from("foo").unwrap(); + let _: String = "foo".try_into().unwrap(); + } + let _: String = "foo".to_string().try_into().unwrap(); + let _: String = TryFrom::try_from("foo".to_string()).unwrap(); + let _ = String::try_from("foo".to_string()).unwrap(); + let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); + let _: String = format!("Hello {}", "world").try_into().unwrap(); + let _: String = "".to_owned().try_into().unwrap(); + let _: String = match String::from("_").try_into() { + Ok(a) => a, + Err(_) => "".into(), + }; + // FIXME this is a false negative + #[allow(clippy::cmp_owned)] + if String::from("a") == TryInto::::try_into(String::from("a")).unwrap() {} +} diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr new file mode 100644 index 0000000000000..b765727c168f5 --- /dev/null +++ b/tests/ui/useless_conversion_try.stderr @@ -0,0 +1,79 @@ +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:6:13 + | +LL | let _ = T::try_from(val).unwrap(); + | ^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/useless_conversion_try.rs:1:9 + | +LL | #![deny(clippy::useless_conversion)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider removing `T::try_from()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:7:5 + | +LL | val.try_into().unwrap() + | ^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:29:21 + | +LL | let _: String = "foo".to_string().try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:30:21 + | +LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `TryFrom::try_from()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:31:13 + | +LL | let _ = String::try_from("foo".to_string()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `String::try_from()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:32:13 + | +LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `String::try_from()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:33:21 + | +LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:34:21 + | +LL | let _: String = "".to_owned().try_into().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: useless conversion to the same type + --> $DIR/useless_conversion_try.rs:35:27 + | +LL | let _: String = match String::from("_").try_into() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing `.try_into()` + +error: aborting due to 9 previous errors + From 84eae777c1ea16bd0b1b8e86f344714edd31b35e Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Thu, 21 May 2020 15:39:52 +0200 Subject: [PATCH 386/695] submodules: Update RLS and Rustfmt --- Cargo.lock | 90 +++++++++++++++++++++++------------------------ src/tools/rls | 2 +- src/tools/rustfmt | 2 +- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1cc254b9b9805..98ddad867fa3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2784,9 +2784,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.33" +version = "2.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54322b696f7df20e0d79d0244a1088f387b7164a5f17987c4ab984dec1a23e42" +checksum = "cc9caecf1286a3ed28d3ae35207a178ba12e58de95540781e5c6cba05e0f0833" dependencies = [ "bitflags", "clap", @@ -3212,9 +3212,9 @@ dependencies = [ [[package]] name = "rustc-ap-arena" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfcfbb0ddfd533abf8c076e3b49d1e5042d1962526a12ce2c66d514b24cca3" +checksum = "fdaf0295fc40b10ec1091aad1a1760b4bb3b4e7c4f77d543d1a2e9d50a01e6b1" dependencies = [ "rustc-ap-rustc_data_structures", "smallvec 1.4.0", @@ -3222,15 +3222,15 @@ dependencies = [ [[package]] name = "rustc-ap-graphviz" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490bb07b014a7f9531bde33c905a805e08095dbefdb4c9988a1b19fe6d019fd" +checksum = "8028e8cdb4eb71810d0c22a5a5e1e3106c81123be63ce7f044b6d4ac100d8941" [[package]] name = "rustc-ap-rustc_ast" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "189f16dbb8dd11089274c9ced58b0cae9e1ea3e434a58f3db683817eda849e58" +checksum = "16e9e502bb3a5568433db1cf2fb1f1e1074934636069cf744ad7c77b58e1428e" dependencies = [ "log", "rustc-ap-rustc_data_structures", @@ -3245,9 +3245,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast_passes" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe619609b56a617fa986332b066d53270093c816d8ff8281fc90e1dbe74c1cc" +checksum = "faf35ffecab28f97f7ac01cf6a13afaca6408529d15eb95f317a43b2ffb88933" dependencies = [ "itertools 0.8.0", "log", @@ -3264,21 +3264,20 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast_pretty" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ab1495f7b420e937688749c1da5763aaabd6ebe8cacb758665a0b8481da094" +checksum = "3684ed43dc552f1e030e3f7a5a300a7a834bdda4e9e00ab80284be4220d8c603" dependencies = [ "log", "rustc-ap-rustc_ast", - "rustc-ap-rustc_data_structures", "rustc-ap-rustc_span", ] [[package]] name = "rustc-ap-rustc_attr" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e057495724c60729c1d1d9d49374e0b3ebd6d3481cd161b2871f52fe017b7b5" +checksum = "31b413927daa666983b3b49227f9ac218aa29254546abdb585f20cd71c391870" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", @@ -3289,19 +3288,19 @@ dependencies = [ "rustc-ap-rustc_session", "rustc-ap-rustc_span", "rustc-ap-serialize", - "smallvec 1.4.0", + "version_check", ] [[package]] name = "rustc-ap-rustc_data_structures" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2130997667833692f4bec4681d0e73b066d5a01dac1d8a68f22068b82bf173a" +checksum = "4b1c6069e5c522657f1c6f5ab33074e097092f48e804cc896d337e319aacbd60" dependencies = [ "bitflags", "cfg-if", "crossbeam-utils 0.7.2", - "ena 0.13.1", + "ena 0.14.0", "indexmap", "jobserver", "lazy_static", @@ -3317,14 +3316,15 @@ dependencies = [ "rustc-rayon-core", "smallvec 1.4.0", "stable_deref_trait", + "stacker", "winapi 0.3.8", ] [[package]] name = "rustc-ap-rustc_errors" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "908e1ea187c6bb368af4ba6db980001e920515e67371ddc4086e749baabe6080" +checksum = "0c374e89b3c9714869ef86076942155383804ba6778c26be2169d324563c31f9" dependencies = [ "annotate-snippets", "atty", @@ -3340,9 +3340,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_expand" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50066a75bca872ff933b0ee8a582d18ef1876c8054a392f60c39e538446bfb00" +checksum = "259d2a7aa7a12f3c99a4ce4123643ec065f1a26f8e89be1f9bedd9757ea53fdc" dependencies = [ "log", "rustc-ap-rustc_ast", @@ -3362,9 +3362,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_feature" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fb53e1710e6de7c2e371ca56c857b79f9b399aba58aa6b6fbed6e2f677d3f6" +checksum = "c0296fbc29b629d5ae2ebee1bbf0407bb22de04d26d87216c20899b79579ccb3" dependencies = [ "lazy_static", "rustc-ap-rustc_data_structures", @@ -3373,15 +3373,15 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_fs_util" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3f91357e5e468fc2729211571d769723c728a34e200d90a70164e945f881e09" +checksum = "34734f6cc681399630acd836a14207c6b5b9671a290cc7cad0354b0a4d71b3c9" [[package]] name = "rustc-ap-rustc_index" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32220c3e6cdf226f38e4474b747dca15f3106bb680c74f10b299af3f6cdb1663" +checksum = "d1e4508753d71d3523209c2ca5086db15a1413e71ebf17ad5412bb7ced5e44c2" dependencies = [ "rustc-ap-serialize", "smallvec 1.4.0", @@ -3389,18 +3389,18 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_lexer" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b324d2a2bacad344e53e182e5ca04ffb74745b932849aa074f8f7fec8177da5" +checksum = "42b9fcd8407e322908a721262fbc0b35b5f3c35bb173a26dd1e0070bde336e33" dependencies = [ "unicode-xid 0.2.0", ] [[package]] name = "rustc-ap-rustc_macros" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59686c56d5f1b3ed47d0f070c257ed35caf24ecf2d744dd11fe44b1014baee0f" +checksum = "3d104115a689367d2e0bcd99f37e0ebd6b9c8c78bab0d9cbea5bae86323601b5" dependencies = [ "proc-macro2 1.0.3", "quote 1.0.2", @@ -3410,9 +3410,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_parse" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfb0c11c591ec5f87bbadb10819795abc9035ff79a26703c1b6c9487ac51f49" +checksum = "afaaab91853fc5a3916785ccae727a4433359d9787c260d42b96a2265fe5b287" dependencies = [ "bitflags", "log", @@ -3424,15 +3424,14 @@ dependencies = [ "rustc-ap-rustc_lexer", "rustc-ap-rustc_session", "rustc-ap-rustc_span", - "smallvec 1.4.0", "unicode-normalization", ] [[package]] name = "rustc-ap-rustc_session" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1a194b1a81d7233ee492847638dc9ebdb7d084300e5ade8dea0ceaa98f95b9" +checksum = "86e756a57ce6ce1b868e35e64a7e10ab28d49ece80d7c661b07aff5afc6e5d2d" dependencies = [ "getopts", "log", @@ -3450,9 +3449,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_span" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a648146050fed6b58e681ec22488e728f60e16036bb7497c9815e3debd1e4242" +checksum = "21031c3396ee452f4c6e994b67513a633055c57c86d00336afd9d63149518f34" dependencies = [ "cfg-if", "log", @@ -3469,9 +3468,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_target" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cf28798f0988b808e3616713630e4098d68c6f1f41052a2f7e922e094da744" +checksum = "ff21badfbead5b0050391eaad8840f2e4fcb03b6b0fc6006f447443529e9ae6e" dependencies = [ "bitflags", "log", @@ -3484,9 +3483,9 @@ dependencies = [ [[package]] name = "rustc-ap-serialize" -version = "654.0.0" +version = "659.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756e8f526ec7906e132188bf25e3c10a6ee42ab77294ecb3b3602647f0508eef" +checksum = "768b5a305669d934522712bc13502962edfde5128ea63b9e7db4000410be1dc6" dependencies = [ "indexmap", "smallvec 1.4.0", @@ -4459,7 +4458,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.14" +version = "1.4.15" dependencies = [ "annotate-snippets", "bytecount", @@ -4477,6 +4476,7 @@ dependencies = [ "regex", "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", + "rustc-ap-rustc_attr", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_errors", "rustc-ap-rustc_expand", diff --git a/src/tools/rls b/src/tools/rls index 1cb7c09eb2454..23985c621cfd4 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 1cb7c09eb245454648bdecd61fa93bace3041b6d +Subproject commit 23985c621cfd4baa15729ea593b12243c2fd3b6f diff --git a/src/tools/rustfmt b/src/tools/rustfmt index a5cb5d26833cf..aedff61f7ac4f 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit a5cb5d26833cfda6fa2ed35735448953f728bd5e +Subproject commit aedff61f7ac4fc2b287ff76d33f2584e1f63a3af From 489b7e4123f9f85d45335d81f21625d08aa87e1f Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Thu, 28 May 2020 10:44:01 +0200 Subject: [PATCH 387/695] Set CFG_RELEASE for tools in bootstrap/tool.rs Since rustc-ap-* v659 we now need to set CFG_RELEASE for rustc-ap-rustc_attr for `#[cfg(version(...))]` to work. Co-authored-by: Eric Huss --- src/bootstrap/tool.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 8ebad95ea1762..5f58f00a2a24d 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -252,6 +252,10 @@ pub fn prepare_tool_cargo( // own copy cargo.env("LZMA_API_STATIC", "1"); + // CFG_RELEASE is needed by rustfmt (and possibly other tools) which + // import rustc-ap-rustc_attr which requires this to be set for the + // `#[cfg(version(...))]` attribute. + cargo.env("CFG_RELEASE", builder.rust_release()); cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel); cargo.env("CFG_VERSION", builder.rust_version()); cargo.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM); From f20fa1b1bb9888609ed2f7349ef0e030f987a351 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 28 May 2020 15:47:54 +0200 Subject: [PATCH 388/695] Update Cargo.lock --- Cargo.lock | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 98ddad867fa3c..feb9ac96bd047 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,10 +551,12 @@ dependencies = [ "lazy_static", "pulldown-cmark 0.7.1", "quine-mc_cluskey", + "quote 1.0.2", "regex-syntax", "semver 0.9.0", "serde", "smallvec 1.4.0", + "syn 1.0.11", "toml", "unicode-normalization", "url 2.1.0", From bb745d6a1878afecce3689c94e514fdf7831e8a1 Mon Sep 17 00:00:00 2001 From: "Joshua M. Clulow" Date: Thu, 28 May 2020 08:09:10 -0700 Subject: [PATCH 389/695] update data layout for illumos x86 In a recent change, 8b199222cc92667cd0e57595ad435cd0a7526af8, adjustments were made to the data layout we pass to LLVM. Unfortunately, the illumos target was missed in this change. See also: https://github.com/rust-lang/rust/pull/67900 --- src/librustc_target/spec/x86_64_unknown_illumos.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_target/spec/x86_64_unknown_illumos.rs b/src/librustc_target/spec/x86_64_unknown_illumos.rs index 8d461f67397f2..2567ca47ef967 100644 --- a/src/librustc_target/spec/x86_64_unknown_illumos.rs +++ b/src/librustc_target/spec/x86_64_unknown_illumos.rs @@ -13,7 +13,8 @@ pub fn target() -> TargetResult { target_endian: "little".to_string(), target_pointer_width: "64".to_string(), target_c_int_width: "32".to_string(), - data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(), + data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + .to_string(), arch: "x86_64".to_string(), target_os: "illumos".to_string(), target_env: String::new(), From 914ff97f2bac425c35d563693f1b823fae8cc8b0 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 28 May 2020 17:19:30 +0200 Subject: [PATCH 390/695] Temp fix: don't run cargo lint tests in rustc test suite --- src/tools/clippy/tests/compile-test.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 2758b9a7e7604..1c4914a470c9b 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -153,6 +153,9 @@ fn run_ui_toml(config: &mut compiletest::Config) { } fn run_ui_cargo(config: &mut compiletest::Config) { + if cargo::is_rustc_test_suite() { + return; + } fn run_tests( config: &compiletest::Config, filter: &Option, From b6c58f0d723d6178506773fa9a4dba9de08ce90a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 28 May 2020 17:19:30 +0200 Subject: [PATCH 391/695] Temp fix: don't run cargo lint tests in rustc test suite --- tests/compile-test.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 2758b9a7e7604..1c4914a470c9b 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -153,6 +153,9 @@ fn run_ui_toml(config: &mut compiletest::Config) { } fn run_ui_cargo(config: &mut compiletest::Config) { + if cargo::is_rustc_test_suite() { + return; + } fn run_tests( config: &compiletest::Config, filter: &Option, From 4329261095ec008afe12531a02c45a2696314d6d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 28 May 2020 08:23:23 -0700 Subject: [PATCH 392/695] Remove rustc-ux-guidelines --- src/doc/rustc-ux-guidelines.md | 90 ---------------------------------- 1 file changed, 90 deletions(-) delete mode 100644 src/doc/rustc-ux-guidelines.md diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md deleted file mode 100644 index b626923bcb59c..0000000000000 --- a/src/doc/rustc-ux-guidelines.md +++ /dev/null @@ -1,90 +0,0 @@ -% Rustc UX guidelines - -Don't forget the user. Whether human or another program, such as an IDE, a -good user experience with the compiler goes a long way toward making developers' -lives better. We do not want users to be baffled by compiler output or -learn arcane patterns to compile their program. - -## Error, Warning, Help, Note Messages - -When the compiler detects a problem, it can emit one of the following: an error, a warning, -a note, or a help message. - -An `error` is emitted when the compiler detects a problem that makes it unable - to compile the program, either because the program is invalid or the - programmer has decided to make a specific `warning` into an error. - -A `warning` is emitted when the compiler detects something odd about a -program. For instance, dead code and unused `Result` values. - -A `help` message is emitted following an `error` or `warning` to give additional -information to the user about how to solve their problem. - -A `note` is emitted to identify additional circumstances and parts of the code -that caused the warning or error. For example, the borrow checker will note any -previous conflicting borrows. - -* Write in plain simple English. If your message, when shown on a – possibly -small – screen (which hasn't been cleaned for a while), cannot be understood -by a normal programmer, who just came out of bed after a night partying, it's -too complex. -* `Errors` and `Warnings` should not suggest how to fix the problem. A `Help` -message should be emitted instead. -* `Error`, `Warning`, `Note`, and `Help` messages start with a lowercase -letter and do not end with punctuation. -* Error messages should be succinct. Users will see these error messages many -times, and more verbose descriptions can be viewed with the `--explain` flag. -That said, don't make it so terse that it's hard to understand. -* The word "illegal" is illegal. Prefer "invalid" or a more specific word -instead. -* Errors should document the span of code where they occur – the `span_..` -methods allow to easily do this. Also `note` other spans that have contributed -to the error if the span isn't too large. -* When emitting a message with span, try to reduce the span to the smallest -amount possible that still signifies the issue -* Try not to emit multiple error messages for the same error. This may require -detecting duplicates. -* When the compiler has too little information for a specific error message, -lobby for annotations for library code that allow adding more. For example see -`#[on_unimplemented]`. Use these annotations when available! -* Keep in mind that Rust's learning curve is rather steep, and that the -compiler messages are an important learning tool. - -## Error Explanations - -Error explanations are long form descriptions of error messages provided with -the compiler. They are accessible via the `--explain` flag. Each explanation -comes with an example of how to trigger it and advice on how to fix it. - -Please read [RFC 1567](https://github.com/rust-lang/rfcs/blob/master/text/1567-long-error-codes-explanation-normalization.md) -for details on how to format and write long error codes. - -* All of them are accessible [online](http://doc.rust-lang.org/error-index.html), - which are auto-generated from rustc source code in different places: - [librustc](https://github.com/rust-lang/rust/blob/master/src/librustc/error_codes.rs), - [librustc_ast](https://github.com/rust-lang/rust/blob/master/src/librustc_ast/error_codes.rs), - [librustc_borrowck](https://github.com/rust-lang/rust/blob/master/src/librustc_borrowck/error_codes.rs), - [librustc_metadata](https://github.com/rust-lang/rust/blob/master/src/librustc_metadata/error_codes.rs), - [librustc_mir](https://github.com/rust-lang/rust/blob/master/src/librustc_mir/error_codes.rs), - [librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/error_codes.rs), - [librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/error_codes.rs), - [librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/error_codes.rs), - [librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/error_codes.rs), - [librustc_plugin_impl](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/error_codes.rs), - [librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/error_codes.rs). -* Explanations have full markdown support. Use it, especially to highlight -code with backticks. -* When talking about the compiler, call it `the compiler`, not `Rust` or -`rustc`. - -## Compiler Flags - -* Flags should be orthogonal to each other. For example, if we'd have a -json-emitting variant of multiple actions `foo` and `bar`, an additional ---json flag is better than adding `--foo-json` and `--bar-json`. -* Always give options a long descriptive name, if only for more -understandable compiler scripts. -* The `--verbose` flag is for adding verbose information to `rustc` output -when not compiling a program. For example, using it with the `--version` flag -gives information about the hashes of the code. -* Experimental flags and options must be guarded behind the `-Z unstable-options` flag. From 42a4f5ac50821d0a82c9593f049a2c3f21e922e9 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 29 May 2020 00:40:41 +0800 Subject: [PATCH 393/695] Fix grammar in liballoc raw_vec --- src/liballoc/raw_vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 2bd4733db420b..56e284a12fa83 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -315,7 +315,7 @@ impl RawVec { /// `used_capacity + needed_extra_capacity` elements. If it doesn't already, /// will reallocate the minimum possible amount of memory necessary. /// Generally this will be exactly the amount of memory necessary, - /// but in principle the allocator is free to give back more than + /// but in principle the allocator is free to give back more than what /// we asked for. /// /// If `used_capacity` exceeds `self.capacity()`, this may fail to actually allocate From 1eef0c3c1e294c798633c8ce416cd70ceaf4e2d9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 28 May 2020 19:44:53 +0300 Subject: [PATCH 394/695] rustc_lint: Remove `unused_crate_dependencies` from the `unused` group --- src/librustc_lint/lib.rs | 1 - src/test/ui/unused-crate-deps/lint-group.rs | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/unused-crate-deps/lint-group.rs diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index ee27342541c93..b791d313fc4f4 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -276,7 +276,6 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { UNUSED_ALLOCATION, UNUSED_DOC_COMMENTS, UNUSED_EXTERN_CRATES, - UNUSED_CRATE_DEPENDENCIES, UNUSED_FEATURES, UNUSED_LABELS, UNUSED_PARENS, diff --git a/src/test/ui/unused-crate-deps/lint-group.rs b/src/test/ui/unused-crate-deps/lint-group.rs new file mode 100644 index 0000000000000..e21ffb5dec2de --- /dev/null +++ b/src/test/ui/unused-crate-deps/lint-group.rs @@ -0,0 +1,9 @@ +// `unused_crate_dependencies` is not currently in the `unused` group +// due to false positives from Cargo. + +// check-pass +// aux-crate:bar=bar.rs + +#![deny(unused)] + +fn main() {} From 0e3b31c641217542f02b40527b0d299d9534b920 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 28 May 2020 13:23:33 -0400 Subject: [PATCH 395/695] Update src/librustdoc/core.rs --- src/librustdoc/core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 331ce1453e139..99ca7084c30dd 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -228,7 +228,7 @@ where // Whitelist feature-gated lints to avoid feature errors when trying to // allow all lints. - // FIXME(LeSeulArtichaut): handle feature-gated lints properly. + // FIXME(#72694): handle feature-gated lints properly. let unsafe_op_in_unsafe_fn_name = rustc_lint::builtin::UNSAFE_OP_IN_UNSAFE_FN.name; whitelisted_lints.push(warnings_lint_name.to_owned()); From 1bd69702de07858ad9c7ae7ed89c3c99aea64550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 May 2020 10:35:48 -0700 Subject: [PATCH 396/695] Account for `Self` as a type param --- .../trait_impl_difference.rs | 10 ++-- .../self-without-lifetime-constraint.rs | 53 +++++++++++++++++++ .../self-without-lifetime-constraint.stderr | 19 +++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/traits/self-without-lifetime-constraint.rs create mode 100644 src/test/ui/traits/self-without-lifetime-constraint.stderr diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 1b6e5c2116b39..5f14f799fc7aa 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -6,6 +6,7 @@ use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; use rustc_errors::ErrorReported; use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_middle::ty::error::ExpectedFound; @@ -124,15 +125,17 @@ impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { match arg.kind { - hir::TyKind::Slice(_) | hir::TyKind::Tup(_) | hir::TyKind::Array(..) => { - hir::intravisit::walk_ty(self, arg); + hir::TyKind::Rptr(_, ref mut_ty) => { + // We don't want to suggest looking into borrowing `&T` or `&Self`. + hir::intravisit::walk_ty(self, mut_ty.ty); + return; } hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { [segment] if segment .res .map(|res| match res { - hir::def::Res::Def(hir::def::DefKind::TyParam, _) => true, + Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true, _ => false, }) .unwrap_or(false) => @@ -143,5 +146,6 @@ impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { }, _ => {} } + hir::intravisit::walk_ty(self, arg); } } diff --git a/src/test/ui/traits/self-without-lifetime-constraint.rs b/src/test/ui/traits/self-without-lifetime-constraint.rs new file mode 100644 index 0000000000000..99013d32ab8d0 --- /dev/null +++ b/src/test/ui/traits/self-without-lifetime-constraint.rs @@ -0,0 +1,53 @@ +use std::error::Error; +use std::fmt; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum ValueRef<'a> { + Null, + Integer(i64), + Real(f64), + Text(&'a [u8]), + Blob(&'a [u8]), +} + +impl<'a> ValueRef<'a> { + pub fn as_str(&self) -> FromSqlResult<&'a str, &'a &'a str> { + match *self { + ValueRef::Text(t) => { + std::str::from_utf8(t).map_err(|_| FromSqlError::InvalidType).map(|x| (x, &x)) + } + _ => Err(FromSqlError::InvalidType), + } + } +} + +#[derive(Debug)] +#[non_exhaustive] +pub enum FromSqlError { + InvalidType +} + +impl fmt::Display for FromSqlError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "InvalidType") + } +} + +impl Error for FromSqlError {} + +pub type FromSqlResult = Result<(T, K), FromSqlError>; + +pub trait FromSql: Sized { + fn column_result(value: ValueRef<'_>) -> FromSqlResult; +} + +impl FromSql for &str { + fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> { + //~^ ERROR `impl` item signature doesn't match `trait` item signature + value.as_str() + } +} + +pub fn main() { + println!("{}", "Hello World"); +} diff --git a/src/test/ui/traits/self-without-lifetime-constraint.stderr b/src/test/ui/traits/self-without-lifetime-constraint.stderr new file mode 100644 index 0000000000000..6c7abe753e2bf --- /dev/null +++ b/src/test/ui/traits/self-without-lifetime-constraint.stderr @@ -0,0 +1,19 @@ +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/self-without-lifetime-constraint.rs:45:5 + | +LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult; + | -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>` +... +LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), FromSqlError>` + | + = note: expected `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>` + found `fn(ValueRef<'_>) -> std::result::Result<(&str, &&str), _>` +help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + --> $DIR/self-without-lifetime-constraint.rs:41:60 + | +LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult; + | ^^^^ consider borrowing this type parameter in the trait + +error: aborting due to previous error + From 0e857c27e21f82cbff1135bcdf70fe97c1a4b4e8 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 28 May 2020 20:04:49 +0200 Subject: [PATCH 397/695] Update RLS to clippyup branch --- src/tools/rls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rls b/src/tools/rls index 23985c621cfd4..085f24b9ecbc0 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 23985c621cfd4baa15729ea593b12243c2fd3b6f +Subproject commit 085f24b9ecbc0e90d204cab1c111c4abe4608ce0 From fa351eefa0f547b9263984e71e1297052862a20f Mon Sep 17 00:00:00 2001 From: Nathan Corbyn Date: Thu, 21 May 2020 19:51:39 +0100 Subject: [PATCH 398/695] Fix ICE with explicit late-bound lifetimes --- src/librustc_typeck/astconv.rs | 310 ++++++++++++-------- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/mod.rs | 26 +- src/test/ui/issues/issue-72278.rs | 19 ++ src/test/ui/issues/issue-72278.stderr | 15 + 5 files changed, 241 insertions(+), 131 deletions(-) create mode 100644 src/test/ui/issues/issue-72278.rs create mode 100644 src/test/ui/issues/issue-72278.stderr diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9a5fe9552d35a..12edfed19c07e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -123,7 +123,22 @@ enum ConvertedBindingKind<'a, 'tcx> { Constraint(&'a [hir::GenericBound<'a>]), } -#[derive(PartialEq)] +/// New-typed boolean indicating whether explicit late-bound lifetimes +/// are present in a set of generic arguments. +/// +/// For example if we have some method `fn f<'a>(&'a self)` implemented +/// for some type `T`, although `f` is generic in the lifetime `'a`, `'a` +/// is late-bound so should not be provided explicitly. Thus, if `f` is +/// instantiated with some generic arguments providing `'a` explicitly, +/// we taint those arguments with `ExplicitLateBound::Yes` so that we +/// can provide an appropriate diagnostic later. +#[derive(Copy, Clone, PartialEq)] +pub enum ExplicitLateBound { + Yes, + No, +} + +#[derive(Copy, Clone, PartialEq)] enum GenericArgPosition { Type, Value, // e.g., functions @@ -132,6 +147,7 @@ enum GenericArgPosition { /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. +#[derive(Clone, Default)] pub struct GenericArgCountMismatch { /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). pub reported: Option, @@ -139,6 +155,14 @@ pub struct GenericArgCountMismatch { pub invalid_args: Vec, } +/// Decorates the result of a generic argument count mismatch +/// check with whether explicit late bounds were provided. +#[derive(Clone)] +pub struct GenericArgCountResult { + pub explicit_late_bound: ExplicitLateBound, + pub correct: Result<(), GenericArgCountMismatch>, +} + impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region( &self, @@ -271,7 +295,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def: &ty::Generics, seg: &hir::PathSegment<'_>, is_method_call: bool, - ) -> Result<(), GenericArgCountMismatch> { + ) -> GenericArgCountResult { let empty_args = hir::GenericArgs::none(); let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); Self::check_generic_arg_count( @@ -295,7 +319,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { position: GenericArgPosition, has_self: bool, infer_args: bool, - ) -> Result<(), GenericArgCountMismatch> { + ) -> GenericArgCountResult { // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. // that lifetimes will proceed types. So it suffices to check the number of each generic // arguments in order to validate them with respect to the generic parameters. @@ -320,105 +344,86 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); } - // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present. - let mut explicit_lifetimes = Ok(()); - if !infer_lifetimes { - if let Some(span_late) = def.has_late_bound_regions { - let msg = "cannot specify lifetime arguments explicitly \ - if late bound lifetime parameters are present"; - let note = "the late bound lifetime parameter is introduced here"; - let span = args.args[0].span(); - if position == GenericArgPosition::Value - && arg_counts.lifetimes != param_counts.lifetimes - { - explicit_lifetimes = Err(true); - let mut err = tcx.sess.struct_span_err(span, msg); - err.span_note(span_late, note); - err.emit(); - } else { - explicit_lifetimes = Err(false); - let mut multispan = MultiSpan::from_span(span); - multispan.push_span_label(span_late, note.to_string()); - tcx.struct_span_lint_hir( - LATE_BOUND_LIFETIME_ARGUMENTS, - args.args[0].id(), - multispan, - |lint| lint.build(msg).emit(), - ); - } + let explicit_late_bound = + Self::prohibit_explicit_late_bound_lifetimes(tcx, def, args, position); + + let check_kind_count = |kind, + required, + permitted, + provided, + offset, + unexpected_spans: &mut Vec, + silent| { + debug!( + "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", + kind, required, permitted, provided, offset + ); + // We enforce the following: `required` <= `provided` <= `permitted`. + // For kinds without defaults (e.g.., lifetimes), `required == permitted`. + // For other kinds (i.e., types), `permitted` may be greater than `required`. + if required <= provided && provided <= permitted { + return Ok(()); } - } - let check_kind_count = - |kind, required, permitted, provided, offset, unexpected_spans: &mut Vec| { - debug!( - "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", - kind, required, permitted, provided, offset - ); - // We enforce the following: `required` <= `provided` <= `permitted`. - // For kinds without defaults (e.g.., lifetimes), `required == permitted`. - // For other kinds (i.e., types), `permitted` may be greater than `required`. - if required <= provided && provided <= permitted { - return Ok(()); - } - - // Unfortunately lifetime and type parameter mismatches are typically styled - // differently in diagnostics, which means we have a few cases to consider here. - let (bound, quantifier) = if required != permitted { - if provided < required { - (required, "at least ") - } else { - // provided > permitted - (permitted, "at most ") - } - } else { - (required, "") - }; + if silent { + return Err(true); + } - let (spans, label) = if required == permitted && provided > permitted { - // In the case when the user has provided too many arguments, - // we want to point to the unexpected arguments. - let spans: Vec = args.args[offset + permitted..offset + provided] - .iter() - .map(|arg| arg.span()) - .collect(); - unexpected_spans.extend(spans.clone()); - (spans, format!("unexpected {} argument", kind)) + // Unfortunately lifetime and type parameter mismatches are typically styled + // differently in diagnostics, which means we have a few cases to consider here. + let (bound, quantifier) = if required != permitted { + if provided < required { + (required, "at least ") } else { - ( - vec![span], - format!( - "expected {}{} {} argument{}", - quantifier, - bound, - kind, - pluralize!(bound), - ), - ) - }; - - let mut err = tcx.sess.struct_span_err_with_code( - spans.clone(), - &format!( - "wrong number of {} arguments: expected {}{}, found {}", - kind, quantifier, bound, provided, - ), - DiagnosticId::Error("E0107".into()), - ); - for span in spans { - err.span_label(span, label.as_str()); + // provided > permitted + (permitted, "at most ") } - err.emit(); + } else { + (required, "") + }; - Err(true) + let (spans, label) = if required == permitted && provided > permitted { + // In the case when the user has provided too many arguments, + // we want to point to the unexpected arguments. + let spans: Vec = args.args[offset + permitted..offset + provided] + .iter() + .map(|arg| arg.span()) + .collect(); + unexpected_spans.extend(spans.clone()); + (spans, format!("unexpected {} argument", kind)) + } else { + ( + vec![span], + format!( + "expected {}{} {} argument{}", + quantifier, + bound, + kind, + pluralize!(bound), + ), + ) }; - let mut arg_count_correct = explicit_lifetimes; + let mut err = tcx.sess.struct_span_err_with_code( + spans.clone(), + &format!( + "wrong number of {} arguments: expected {}{}, found {}", + kind, quantifier, bound, provided, + ), + DiagnosticId::Error("E0107".into()), + ); + for span in spans { + err.span_label(span, label.as_str()); + } + err.emit(); + + Err(true) + }; + + let mut arg_count_correct = Ok(()); let mut unexpected_spans = vec![]; - if arg_count_correct.is_ok() - && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) - { + if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { arg_count_correct = check_kind_count( "lifetime", param_counts.lifetimes, @@ -426,6 +431,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.lifetimes, 0, &mut unexpected_spans, + explicit_late_bound == ExplicitLateBound::Yes, ) .and(arg_count_correct); } @@ -438,6 +444,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.consts, arg_counts.lifetimes + arg_counts.types, &mut unexpected_spans, + false, ) .and(arg_count_correct); } @@ -451,14 +458,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.types, arg_counts.lifetimes, &mut unexpected_spans, + false, ) .and(arg_count_correct); } - arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { - reported: if reported_err { Some(ErrorReported) } else { None }, - invalid_args: unexpected_spans, - }) + GenericArgCountResult { + explicit_late_bound, + correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { + reported: if reported_err { Some(ErrorReported) } else { None }, + invalid_args: unexpected_spans, + }), + } } /// Report an error that a generic argument did not match the generic parameter that was @@ -512,7 +523,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option>, - arg_count_correct: bool, + arg_count: GenericArgCountResult, args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, mut inferred_kind: impl FnMut( @@ -585,10 +596,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // input. We try to handle both sensibly. match (args.peek(), params.peek()) { (Some(&arg), Some(¶m)) => { - match (arg, ¶m.kind) { - (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime) - | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) - | (GenericArg::Const(_), GenericParamDefKind::Const) => { + match (arg, ¶m.kind, arg_count.explicit_late_bound) { + (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) + | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _) + | (GenericArg::Const(_), GenericParamDefKind::Const, _) => { substs.push(provided_kind(param, arg)); args.next(); params.next(); @@ -596,6 +607,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ( GenericArg::Type(_) | GenericArg::Const(_), GenericParamDefKind::Lifetime, + _, ) => { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. @@ -603,12 +615,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { force_infer_lt = Some(arg); params.next(); } - (_, kind) => { + (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => { + // We've come across a lifetime when we expected something else in + // the presence of explicit late bounds. This is most likely + // due to the presence of the explicit bound so we're just going to + // ignore it. + args.next(); + } + (_, kind, _) => { // We expected one kind of parameter, but the user provided // another. This is an error. However, if we already know that // the arguments don't match up with the parameters, we won't issue // an additional error, as the user already knows what's wrong. - if arg_count_correct { + if arg_count.correct.is_ok() + && arg_count.explicit_late_bound == ExplicitLateBound::No + { Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr()); } @@ -624,17 +645,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (Some(&arg), None) => { // We should never be able to reach this point with well-formed input. - // There are two situations in which we can encounter this issue. + // There are three situations in which we can encounter this issue. // // 1. The number of arguments is incorrect. In this case, an error - // will already have been emitted, and we can ignore it. This case - // also occurs when late-bound lifetime parameters are present, yet - // the lifetime arguments have also been explicitly specified by the + // will already have been emitted, and we can ignore it. + // 2. There are late-bound lifetime parameters present, yet the + // lifetime arguments have also been explicitly specified by the // user. - // 2. We've inferred some lifetimes, which have been provided later (i.e. + // 3. We've inferred some lifetimes, which have been provided later (i.e. // after a type or const). We want to throw an error in this case. - if arg_count_correct { + if arg_count.correct.is_ok() + && arg_count.explicit_late_bound == ExplicitLateBound::No + { let kind = arg.descr(); assert_eq!(kind, "lifetime"); let provided = @@ -699,8 +722,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args: &'a hir::GenericArgs<'_>, infer_args: bool, self_ty: Option>, - ) -> (SubstsRef<'tcx>, Vec>, Result<(), GenericArgCountMismatch>) - { + ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). @@ -726,7 +748,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(self_ty.is_none() && parent_substs.is_empty()); } - let arg_count_correct = Self::check_generic_arg_count( + let arg_count = Self::check_generic_arg_count( tcx, span, &generic_params, @@ -761,7 +783,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs, self_ty.is_some(), self_ty, - arg_count_correct.is_ok(), + arg_count.clone(), // Provide the generic args, and whether types should be inferred. |did| { if did == def_id { @@ -880,7 +902,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_params, self_ty, substs ); - (substs, assoc_bindings, arg_count_correct) + (substs, assoc_bindings, arg_count) } crate fn create_substs_for_associated_item( @@ -1011,14 +1033,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, - ) -> Result<(), GenericArgCountMismatch> { + ) -> GenericArgCountResult { let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - let (substs, assoc_bindings, arg_count_correct) = self.create_substs_for_ast_trait_ref( + let (substs, assoc_bindings, arg_count) = self.create_substs_for_ast_trait_ref( trait_ref.path.span, trait_def_id, self_ty, @@ -1048,7 +1070,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_ref, bounds, poly_trait_ref ); - arg_count_correct + arg_count } /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct @@ -1076,7 +1098,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, - ) -> Result<(), GenericArgCountMismatch> { + ) -> GenericArgCountResult { self.instantiate_poly_trait_ref_inner( &poly_trait_ref.trait_ref, poly_trait_ref.span, @@ -1166,8 +1188,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment<'a>, - ) -> (SubstsRef<'tcx>, Vec>, Result<(), GenericArgCountMismatch>) - { + ) -> (SubstsRef<'tcx>, Vec>, GenericArgCountResult) { debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); @@ -1515,9 +1536,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in trait_bounds.iter().rev() { - if let Err(GenericArgCountMismatch { - invalid_args: cur_potential_assoc_types, .. - }) = self.instantiate_poly_trait_ref( + if let GenericArgCountResult { + correct: + Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), + .. + } = self.instantiate_poly_trait_ref( trait_bound, Constness::NotConst, dummy_self, @@ -2473,6 +2496,47 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_label(span, "associated type not allowed here").emit(); } + /// Prohibits explicit lifetime arguments if late-bound lifetime parameters + /// are present. This is used both for datatypes and function calls. + fn prohibit_explicit_late_bound_lifetimes( + tcx: TyCtxt<'_>, + def: &ty::Generics, + args: &hir::GenericArgs<'_>, + position: GenericArgPosition, + ) -> ExplicitLateBound { + let param_counts = def.own_counts(); + let arg_counts = args.own_counts(); + let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0; + + if infer_lifetimes { + ExplicitLateBound::No + } else if let Some(span_late) = def.has_late_bound_regions { + let msg = "cannot specify lifetime arguments explicitly \ + if late bound lifetime parameters are present"; + let note = "the late bound lifetime parameter is introduced here"; + let span = args.args[0].span(); + if position == GenericArgPosition::Value + && arg_counts.lifetimes != param_counts.lifetimes + { + let mut err = tcx.sess.struct_span_err(span, msg); + err.span_note(span_late, note); + err.emit(); + } else { + let mut multispan = MultiSpan::from_span(span); + multispan.push_span_label(span_late, note.to_string()); + tcx.struct_span_lint_hir( + LATE_BOUND_LIFETIME_ARGUMENTS, + args.args[0].id(), + multispan, + |lint| lint.build(msg).emit(), + ); + } + ExplicitLateBound::Yes + } else { + ExplicitLateBound::No + } + } + // FIXME(eddyb, varkor) handle type paths here too, not just value ones. pub fn def_ids_for_value_path_segments( &self, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 410c5efdf37d4..35094c69037b6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { parent_substs, false, None, - arg_count_correct.is_ok(), + arg_count_correct, // Provide the generic args, and whether types should be inferred. |def_id| { // The last component of the returned tuple here is unimportant. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index da711b9d48042..91ebb10303764 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,7 +87,9 @@ mod upvar; mod wfcheck; pub mod writeback; -use crate::astconv::{AstConv, GenericArgCountMismatch, PathSeg}; +use crate::astconv::{ + AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, +}; use rustc_ast::ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_attr as attr; @@ -5495,11 +5497,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parameter internally, but we don't allow users to specify the // parameter's value explicitly, so we have to do some error- // checking here. - if let Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }) = - AstConv::check_generic_arg_count_for_call( - tcx, span, &generics, &seg, false, // `is_method_call` - ) - { + if let GenericArgCountResult { + correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), + .. + } = AstConv::check_generic_arg_count_for_call( + tcx, span, &generics, &seg, false, // `is_method_call` + ) { infer_args_for_err.insert(index); self.set_tainted_by_errors(); // See issue #53251. } @@ -5555,6 +5558,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // escaping late-bound regions, and nor should the base type scheme. let ty = tcx.type_of(def_id); + let arg_count = GenericArgCountResult { + explicit_late_bound: ExplicitLateBound::No, + correct: if infer_args_for_err.is_empty() { + Ok(()) + } else { + Err(GenericArgCountMismatch::default()) + }, + }; + let substs = self_ctor_substs.unwrap_or_else(|| { AstConv::create_substs_for_generic_args( tcx, @@ -5562,7 +5574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[][..], has_self, self_ty, - infer_args_for_err.is_empty(), + arg_count, // Provide the generic args, and whether types should be inferred. |def_id| { if let Some(&PathSeg(_, index)) = diff --git a/src/test/ui/issues/issue-72278.rs b/src/test/ui/issues/issue-72278.rs new file mode 100644 index 0000000000000..92fd1f73a937f --- /dev/null +++ b/src/test/ui/issues/issue-72278.rs @@ -0,0 +1,19 @@ +// run-pass + +#![allow(unused)] + +struct S; + +impl S { + fn func<'a, U>(&'a self) -> U { + todo!() + } +} + +fn dont_crash<'a, U>() -> U { + S.func::<'a, U>() + //~^ WARN cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted +} + +fn main() {} diff --git a/src/test/ui/issues/issue-72278.stderr b/src/test/ui/issues/issue-72278.stderr new file mode 100644 index 0000000000000..41dff686bc4ae --- /dev/null +++ b/src/test/ui/issues/issue-72278.stderr @@ -0,0 +1,15 @@ +warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/issue-72278.rs:14:14 + | +LL | fn func<'a, U>(&'a self) -> U { + | -- the late bound lifetime parameter is introduced here +... +LL | S.func::<'a, U>() + | ^^ + | + = note: `#[warn(late_bound_lifetime_arguments)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 + +warning: 1 warning emitted + From 071f0422c6dd897bc61891f96d4448df44d8069f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 28 May 2020 22:12:31 +0300 Subject: [PATCH 399/695] linker: Add a linker rerun hack for gcc versions not supporting -static-pie --- src/librustc_codegen_ssa/back/link.rs | 65 +++++++++++++++++--- src/librustc_target/spec/tests/tests_impl.rs | 5 ++ 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 9a7c4907754b0..b322e9a8fef1c 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -12,7 +12,7 @@ use rustc_session::utils::NativeLibKind; /// need out of the shared crate context before we get rid of it. use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; -use rustc_target::spec::crt_objects::CrtObjectsFallback; +use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel}; @@ -25,16 +25,10 @@ use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FIL use cc::windows_registry; use tempfile::{Builder as TempFileBuilder, TempDir}; -use std::ascii; -use std::char; -use std::env; use std::ffi::OsString; -use std::fmt; -use std::fs; -use std::io; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; -use std::str; +use std::{ascii, char, env, fmt, fs, io, mem, str}; pub fn remove(sess: &Session, path: &Path) { if let Err(e) = fs::remove_file(path) { @@ -543,6 +537,61 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( continue; } + // Detect '-static-pie' used with an older version of gcc or clang not supporting it. + // Fallback from '-static-pie' to '-static' in that case. + if sess.target.target.options.linker_is_gnu + && flavor != LinkerFlavor::Ld + && (out.contains("unrecognized command line option") + || out.contains("unknown argument")) + && (out.contains("-static-pie") || out.contains("--no-dynamic-linker")) + && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie") + { + info!("linker output: {:?}", out); + warn!( + "Linker does not support -static-pie command line option. Retrying with -static instead." + ); + // Mirror `add_(pre,post)_link_objects` to replace CRT objects. + let fallback = crt_objects_fallback(sess, crate_type); + let opts = &sess.target.target.options; + let pre_objects = + if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects }; + let post_objects = + if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects }; + let get_objects = |objects: &CrtObjects, kind| { + objects + .get(&kind) + .iter() + .copied() + .flatten() + .map(|obj| get_object_file_path(sess, obj).into_os_string()) + .collect::>() + }; + let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe); + let post_objects_static_pie = get_objects(post_objects, LinkOutputKind::StaticPicExe); + let mut pre_objects_static = get_objects(pre_objects, LinkOutputKind::StaticNoPicExe); + let mut post_objects_static = get_objects(post_objects, LinkOutputKind::StaticNoPicExe); + // Assume that we know insertion positions for the replacement arguments from replaced + // arguments, which is true for all supported targets. + assert!(pre_objects_static.is_empty() || !pre_objects_static_pie.is_empty()); + assert!(post_objects_static.is_empty() || !post_objects_static_pie.is_empty()); + for arg in cmd.take_args() { + if arg.to_string_lossy() == "-static-pie" { + // Replace the output kind. + cmd.arg("-static"); + } else if pre_objects_static_pie.contains(&arg) { + // Replace the pre-link objects (replace the first and remove the rest). + cmd.args(mem::take(&mut pre_objects_static)); + } else if post_objects_static_pie.contains(&arg) { + // Replace the post-link objects (replace the first and remove the rest). + cmd.args(mem::take(&mut post_objects_static)); + } else { + cmd.arg(arg); + } + } + info!("{:?}", &cmd); + continue; + } + // Here's a terribly awful hack that really shouldn't be present in any // compiler. Here an environment variable is supported to automatically // retry the linker invocation if the linker looks like it segfaulted. diff --git a/src/librustc_target/spec/tests/tests_impl.rs b/src/librustc_target/spec/tests/tests_impl.rs index 4cf186bdd7c1a..fb3f912ffde1a 100644 --- a/src/librustc_target/spec/tests/tests_impl.rs +++ b/src/librustc_target/spec/tests/tests_impl.rs @@ -39,5 +39,10 @@ impl Target { assert_eq!(self.options.lld_flavor, LldFlavor::Link); } } + assert!( + (self.options.pre_link_objects_fallback.is_empty() + && self.options.post_link_objects_fallback.is_empty()) + || self.options.crt_objects_fallback.is_some() + ); } } From 461891a000835b88f44cf095533de92fa3b0b952 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 28 May 2020 23:59:54 +0200 Subject: [PATCH 400/695] remove redundant `mk_const` --- src/librustc_mir/transform/const_prop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index f69343f4d7500..92000e6411354 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -606,7 +606,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Operand::Constant(Box::new(Constant { span, user_ty: None, - literal: self.tcx.mk_const(*ty::Const::from_scalar(self.tcx, scalar, ty)), + literal: ty::Const::from_scalar(self.tcx, scalar, ty), })) } From d4ef1744f53ba0a6658174ed5b89a0935b5eb978 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 29 May 2020 01:19:33 +0200 Subject: [PATCH 401/695] Whitelist #[allow_internal_unstable] This should hopefully work around https://github.com/rust-lang/rust/issues/65023, which currently makes almost every bootstrap fail for me. --- src/librustc_feature/builtin_attrs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index 44971a98cc32f..524a357971029 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -366,7 +366,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // FIXME(#14407) ungated!(rustc_const_stable, Whitelisted, template!(List: r#"feature = "name""#)), gated!( - allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + allow_internal_unstable, Whitelisted, template!(Word, List: "feat1, feat2, ..."), "allow_internal_unstable side-steps feature gating and stability checks", ), gated!( From ce81d15289867f7ec0bba959712d100d3ff6a653 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 28 May 2020 14:40:07 -0700 Subject: [PATCH 402/695] Add test to make sure -Wunused-crate-dependencies works with tests Make sure code in `#[test]` blocks counts as a use of a crate. --- src/test/ui/unused-crate-deps/test-use-ok.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/ui/unused-crate-deps/test-use-ok.rs diff --git a/src/test/ui/unused-crate-deps/test-use-ok.rs b/src/test/ui/unused-crate-deps/test-use-ok.rs new file mode 100644 index 0000000000000..66d6440c9cb9f --- /dev/null +++ b/src/test/ui/unused-crate-deps/test-use-ok.rs @@ -0,0 +1,15 @@ +// Test-only use OK + +// edition:2018 +// check-pass +// aux-crate:bar=bar.rs +// compile-flags:--test + +#![deny(unused_crate_dependencies)] + +fn main() {} + +#[test] +fn test_bar() { + assert_eq!(bar::BAR, "bar"); +} From 04243710a0077ad140b8259c21bc1aac02057a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 May 2020 16:31:48 -0700 Subject: [PATCH 403/695] Account for trailing comma when suggesting `where` clauses Fix #72693. --- src/librustc_middle/ty/diagnostics.rs | 21 ++++++++----------- .../traits/error_reporting/suggestions.rs | 11 +++++++++- src/test/ui/bound-suggestions.rs | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index 613d66d59c55b..96c36d989e928 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -7,7 +7,6 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; -use rustc_span::{BytePos, Span}; impl<'tcx> TyS<'tcx> { /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. @@ -221,18 +220,16 @@ pub fn suggest_constraining_type_param( } } - let where_clause_span = generics.where_clause.span_for_predicates_or_empty_place(); // Account for `fn foo(t: T) where T: Foo,` so we don't suggest two trailing commas. - let mut trailing_comma = false; - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(where_clause_span) { - trailing_comma = snippet.ends_with(','); - } - let where_clause_span = if trailing_comma { - let hi = where_clause_span.hi(); - Span::new(hi - BytePos(1), hi, where_clause_span.ctxt()) - } else { - where_clause_span.shrink_to_hi() - }; + let end = generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(); + let where_clause_span = generics + .where_clause + .predicates + .last() + .map(|p| p.span()) + .unwrap_or(end) + .shrink_to_hi() + .to(end); match ¶m_spans[..] { &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 5c85855535e38..eb281b270ff2a 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -169,8 +169,17 @@ pub trait InferCtxtExt<'tcx> { } fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { + let end = generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(); ( - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), + // Account for `where T: Foo,` so we don't suggest two trailing commas. + generics + .where_clause + .predicates + .last() + .map(|p| p.span()) + .unwrap_or(end) + .shrink_to_hi() + .to(end), format!( "{} {}", if !generics.where_clause.predicates.is_empty() { "," } else { " where" }, diff --git a/src/test/ui/bound-suggestions.rs b/src/test/ui/bound-suggestions.rs index 605a6df838658..562dec9f080de 100644 --- a/src/test/ui/bound-suggestions.rs +++ b/src/test/ui/bound-suggestions.rs @@ -19,7 +19,7 @@ fn test_one_bound(t: T) { } #[allow(dead_code)] -fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug { +fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, { println!("{:?} {:?}", x, y); //~^ ERROR doesn't implement } From 02cc593af04a4f8c338baa1f51c9a4c9c005d729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 29 May 2020 00:00:00 +0000 Subject: [PATCH 404/695] Remove unused mut from long-linker-command-lines test --- src/test/run-make-fulldeps/long-linker-command-lines/foo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-make-fulldeps/long-linker-command-lines/foo.rs b/src/test/run-make-fulldeps/long-linker-command-lines/foo.rs index 96fb16b1fcc8f..f313798de215b 100644 --- a/src/test/run-make-fulldeps/long-linker-command-lines/foo.rs +++ b/src/test/run-make-fulldeps/long-linker-command-lines/foo.rs @@ -90,7 +90,7 @@ fn main() { } let linker_args = read_linker_args(&ok); - for mut arg in linker_args.split('S') { + for arg in linker_args.split('S') { expected_libs.remove(arg); } From 85f4f1c95a3eceae1e69a0fbf995cb7e7737e104 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Fri, 29 May 2020 03:29:01 +0200 Subject: [PATCH 405/695] Clarify the documentation of take --- src/libcore/iter/traits/iterator.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 1c3d95cbb8c35..7f081f732fd58 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -1180,6 +1180,17 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` + /// + /// If less than `n` elements are available, + /// `take` will limit itself to the size of the underlying iterator: + /// + /// ``` + /// let v = vec![1, 2]; + /// let mut iter = v.into_iter().take(5); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), None); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn take(self, n: usize) -> Take From ed503acb460256c878609fa2624b6d37e79d6ee4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 29 May 2020 00:19:06 -0400 Subject: [PATCH 406/695] Revert "Fix rebase fallout" This reverts commit 5685e4dd90ad2f4978c63b9097f0b568e4ce6e5c. --- Cargo.lock | 1 - src/librustc_ast/tokenstream.rs | 2 ++ src/librustc_parse/Cargo.toml | 1 - src/librustc_parse/lib.rs | 4 +--- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1cc254b9b9805..9516188cf366b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4143,7 +4143,6 @@ dependencies = [ "rustc_lexer", "rustc_session", "rustc_span", - "smallvec 1.4.0", "unicode-normalization", ] diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index 9d0199078fa6a..ff3469930c6d3 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -21,6 +21,8 @@ use rustc_macros::HashStable_Generic; use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; +use log::debug; + use std::{iter, mem}; /// When the main rust parser encounters a syntax-extension invocation, it diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml index 0d31a8c7bc1fb..7164c67880863 100644 --- a/src/librustc_parse/Cargo.toml +++ b/src/librustc_parse/Cargo.toml @@ -12,7 +12,6 @@ doctest = false [dependencies] bitflags = "1.0" log = "0.4" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_feature = { path = "../librustc_feature" } diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 8ca3f6c5768af..b6e4e104fb5b9 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -14,9 +14,7 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; -use rustc_span::{FileName, SourceFile, Span, DUMMY_SP}; - -use smallvec::SmallVec; +use rustc_span::{FileName, SourceFile, Span}; use std::mem; use std::path::Path; From 4d4facbe4f0290c511c21167e48074786ad75efd Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 29 May 2020 00:19:08 -0400 Subject: [PATCH 407/695] Revert "Add test for macro_rules! invoking a proc-macro with capture groups" This reverts commit 30c00fd26a24f349df64a7c0f5c3490e9f624322. --- src/test/ui/proc-macro/macro-rules-capture.rs | 18 ------------------ .../ui/proc-macro/macro-rules-capture.stderr | 12 ------------ 2 files changed, 30 deletions(-) delete mode 100644 src/test/ui/proc-macro/macro-rules-capture.rs delete mode 100644 src/test/ui/proc-macro/macro-rules-capture.stderr diff --git a/src/test/ui/proc-macro/macro-rules-capture.rs b/src/test/ui/proc-macro/macro-rules-capture.rs deleted file mode 100644 index 37436567d70f0..0000000000000 --- a/src/test/ui/proc-macro/macro-rules-capture.rs +++ /dev/null @@ -1,18 +0,0 @@ -// aux-build: test-macros.rs - -extern crate test_macros; -use test_macros::recollect_attr; - -macro_rules! reemit { - ($name:ident => $($token:expr)*) => { - - #[recollect_attr] - pub fn $name() { - $($token)*; - } - } -} - -reemit! { foo => 45u32.into() } //~ ERROR type annotations - -fn main() {} diff --git a/src/test/ui/proc-macro/macro-rules-capture.stderr b/src/test/ui/proc-macro/macro-rules-capture.stderr deleted file mode 100644 index 6d512846ff785..0000000000000 --- a/src/test/ui/proc-macro/macro-rules-capture.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/macro-rules-capture.rs:16:24 - | -LL | reemit! { foo => 45u32.into() } - | ------^^^^-- - | | | - | | cannot infer type for type parameter `T` declared on the trait `Into` - | this method call resolves to `T` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0282`. From 1ae7de9a52d295a6c3d21af1915fc95951193b83 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 29 May 2020 00:19:10 -0400 Subject: [PATCH 408/695] Revert "Recursively expand nonterminals" This reverts commit 2af0218bf1ffca0750a352554f20a07b760a30a8. --- src/librustc_ast/tokenstream.rs | 2 + src/librustc_parse/lib.rs | 109 ++++---------------------------- 2 files changed, 16 insertions(+), 95 deletions(-) diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index ff3469930c6d3..7348c41dbe778 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -290,6 +290,8 @@ impl TokenStream { t1.next().is_none() && t2.next().is_none() } + + pub fn map_enumerated TokenTree>(self, mut f: F) -> TokenStream { TokenStream(Lrc::new( self.0 diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index b6e4e104fb5b9..8aea8388d08b9 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -7,20 +7,20 @@ #![feature(or_patterns)] use rustc_ast::ast; -use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{self, IsJoint, TokenStream, TokenTree}; +use rustc_ast::token::{self, Nonterminal, Token, TokenKind, DelimToken}; +use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::symbol::kw; use rustc_span::{FileName, SourceFile, Span}; +use rustc_span::symbol::kw; -use std::mem; use std::path::Path; use std::str; +use std::mem; -use log::{debug, info}; +use log::info; pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); @@ -308,7 +308,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real, sess) { + if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real) { return tokens; } info!( @@ -389,11 +389,7 @@ fn prepend_attrs( // // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. -pub fn tokenstream_probably_equal_for_proc_macro( - first: &TokenStream, - other: &TokenStream, - sess: &ParseSess, -) -> bool { +pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &TokenStream) -> bool { // When checking for `probably_eq`, we ignore certain tokens that aren't // preserved in the AST. Because they are not preserved, the pretty // printer arbitrarily adds or removes them when printing as token @@ -421,83 +417,10 @@ pub fn tokenstream_probably_equal_for_proc_macro( true } - // When comparing two `TokenStream`s, we ignore the `IsJoint` information. - // - // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will - // use `Token.glue` on adjacent tokens with the proper `IsJoint`. - // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`) - // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent - // when determining if two `TokenStream`s are 'probably equal'. - // - // Therefore, we use `break_two_token_op` to convert all tokens - // to the 'unglued' form (if it exists). This ensures that two - // `TokenStream`s which differ only in how their tokens are glued - // will be considered 'probably equal', which allows us to keep spans. - // - // This is important when the original `TokenStream` contained - // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces - // will be omitted when we pretty-print, which can cause the original - // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`, - // leading to some tokens being 'glued' together in one stream but not - // the other. See #68489 for more details. - fn break_tokens(tree: TokenTree) -> impl Iterator { - // In almost all cases, we should have either zero or one levels - // of 'unglueing'. However, in some unusual cases, we may need - // to iterate breaking tokens mutliple times. For example: - // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]' - let mut token_trees: SmallVec<[_; 2]>; - if let TokenTree::Token(token) = &tree { - let mut out = SmallVec::<[_; 2]>::new(); - out.push(token.clone()); - // Iterate to fixpoint: - // * We start off with 'out' containing our initial token, and `temp` empty - // * If we are able to break any tokens in `out`, then `out` will have - // at least one more element than 'temp', so we will try to break tokens - // again. - // * If we cannot break any tokens in 'out', we are done - loop { - let mut temp = SmallVec::<[_; 2]>::new(); - let mut changed = false; - - for token in out.into_iter() { - if let Some((first, second)) = token.kind.break_two_token_op() { - temp.push(Token::new(first, DUMMY_SP)); - temp.push(Token::new(second, DUMMY_SP)); - changed = true; - } else { - temp.push(token); - } - } - out = temp; - if !changed { - break; - } - } - token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect(); - if token_trees.len() != 1 { - debug!("break_tokens: broke {:?} to {:?}", tree, token_trees); - } - } else { - token_trees = SmallVec::new(); - token_trees.push(tree); - } - token_trees.into_iter() - } - - let expand_nt = |tree: TokenTree| { - if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree { - nt_to_tokenstream(nt, sess, *span).into_trees() - } else { - TokenStream::new(vec![(tree, IsJoint::NonJoint)]).into_trees() - } - }; - - // Break tokens after we expand any nonterminals, so that we break tokens - // that are produced as a result of nonterminal expansion. - let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); + let mut t1 = first.trees().filter(semantic_tree); + let mut t2 = other.trees().filter(semantic_tree); for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) { + if !tokentree_probably_equal_for_proc_macro(&t1, &t2) { return false; } } @@ -556,29 +479,25 @@ crate fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bo b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate) } - // Expanded by `tokenstream_probably_equal_for_proc_macro` - (&Interpolated(_), &Interpolated(_)) => unreachable!(), + (&Interpolated(_), &Interpolated(_)) => false, _ => panic!("forgot to add a token?"), } } + // See comments in `Nonterminal::to_tokenstream` for why we care about // *probably* equal here rather than actual equality // // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. -pub fn tokentree_probably_equal_for_proc_macro( - first: &TokenTree, - other: &TokenTree, - sess: &ParseSess, -) -> bool { +pub fn tokentree_probably_equal_for_proc_macro(first: &TokenTree, other: &TokenTree) -> bool { match (first, other) { (TokenTree::Token(token), TokenTree::Token(token2)) => { token_probably_equal_for_proc_macro(token, token2) } (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2, sess) + delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2) } _ => false, } From 1c2b65b1e107abc20dede528d80cb47000f144e0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 29 May 2020 00:19:11 -0400 Subject: [PATCH 409/695] Revert "Move functions to librustc_parse" This reverts commit 7a4c1865fb2f58c57e3f09645515dec8be3022c6. --- src/librustc_ast/token.rs | 56 ++++++++++++++ src/librustc_ast/tokenstream.rs | 121 +++++++++++++++++++++++++++++++ src/librustc_parse/lib.rs | 125 +------------------------------- 3 files changed, 179 insertions(+), 123 deletions(-) diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index 2e2bc380e844f..a5b9c2a95bbea 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -673,6 +673,62 @@ impl Token { Some(Token::new(kind, self.span.to(joint.span))) } + + // See comments in `Nonterminal::to_tokenstream` for why we care about + // *probably* equal here rather than actual equality + crate fn probably_equal_for_proc_macro(&self, other: &Token) -> bool { + if mem::discriminant(&self.kind) != mem::discriminant(&other.kind) { + return false; + } + match (&self.kind, &other.kind) { + (&Eq, &Eq) + | (&Lt, &Lt) + | (&Le, &Le) + | (&EqEq, &EqEq) + | (&Ne, &Ne) + | (&Ge, &Ge) + | (&Gt, &Gt) + | (&AndAnd, &AndAnd) + | (&OrOr, &OrOr) + | (&Not, &Not) + | (&Tilde, &Tilde) + | (&At, &At) + | (&Dot, &Dot) + | (&DotDot, &DotDot) + | (&DotDotDot, &DotDotDot) + | (&DotDotEq, &DotDotEq) + | (&Comma, &Comma) + | (&Semi, &Semi) + | (&Colon, &Colon) + | (&ModSep, &ModSep) + | (&RArrow, &RArrow) + | (&LArrow, &LArrow) + | (&FatArrow, &FatArrow) + | (&Pound, &Pound) + | (&Dollar, &Dollar) + | (&Question, &Question) + | (&Whitespace, &Whitespace) + | (&Comment, &Comment) + | (&Eof, &Eof) => true, + + (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b, + + (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b, + + (&DocComment(a), &DocComment(b)) | (&Shebang(a), &Shebang(b)) => a == b, + + (&Literal(a), &Literal(b)) => a == b, + + (&Lifetime(a), &Lifetime(b)) => a == b, + (&Ident(a, b), &Ident(c, d)) => { + b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate) + } + + (&Interpolated(_), &Interpolated(_)) => false, + + _ => panic!("forgot to add a token?"), + } + } } impl PartialEq for Token { diff --git a/src/librustc_ast/tokenstream.rs b/src/librustc_ast/tokenstream.rs index 7348c41dbe778..075aaa7e5bc01 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -68,6 +68,23 @@ impl TokenTree { } } + // See comments in `Nonterminal::to_tokenstream` for why we care about + // *probably* equal here rather than actual equality + // + // This is otherwise the same as `eq_unspanned`, only recursing with a + // different method. + pub fn probably_equal_for_proc_macro(&self, other: &TokenTree) -> bool { + match (self, other) { + (TokenTree::Token(token), TokenTree::Token(token2)) => { + token.probably_equal_for_proc_macro(token2) + } + (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { + delim == delim2 && tts.probably_equal_for_proc_macro(&tts2) + } + _ => false, + } + } + /// Retrieves the TokenTree's span. pub fn span(&self) -> Span { match self { @@ -290,7 +307,111 @@ impl TokenStream { t1.next().is_none() && t2.next().is_none() } + // See comments in `Nonterminal::to_tokenstream` for why we care about + // *probably* equal here rather than actual equality + // + // This is otherwise the same as `eq_unspanned`, only recursing with a + // different method. + pub fn probably_equal_for_proc_macro(&self, other: &TokenStream) -> bool { + // When checking for `probably_eq`, we ignore certain tokens that aren't + // preserved in the AST. Because they are not preserved, the pretty + // printer arbitrarily adds or removes them when printing as token + // streams, making a comparison between a token stream generated from an + // AST and a token stream which was parsed into an AST more reliable. + fn semantic_tree(tree: &TokenTree) -> bool { + if let TokenTree::Token(token) = tree { + if let + // The pretty printer tends to add trailing commas to + // everything, and in particular, after struct fields. + | token::Comma + // The pretty printer emits `NoDelim` as whitespace. + | token::OpenDelim(DelimToken::NoDelim) + | token::CloseDelim(DelimToken::NoDelim) + // The pretty printer collapses many semicolons into one. + | token::Semi + // The pretty printer collapses whitespace arbitrarily and can + // introduce whitespace from `NoDelim`. + | token::Whitespace + // The pretty printer can turn `$crate` into `::crate_name` + | token::ModSep = token.kind { + return false; + } + } + true + } + // When comparing two `TokenStream`s, we ignore the `IsJoint` information. + // + // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will + // use `Token.glue` on adjacent tokens with the proper `IsJoint`. + // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`) + // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent + // when determining if two `TokenStream`s are 'probably equal'. + // + // Therefore, we use `break_two_token_op` to convert all tokens + // to the 'unglued' form (if it exists). This ensures that two + // `TokenStream`s which differ only in how their tokens are glued + // will be considered 'probably equal', which allows us to keep spans. + // + // This is important when the original `TokenStream` contained + // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces + // will be omitted when we pretty-print, which can cause the original + // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`, + // leading to some tokens being 'glued' together in one stream but not + // the other. See #68489 for more details. + fn break_tokens(tree: TokenTree) -> impl Iterator { + // In almost all cases, we should have either zero or one levels + // of 'unglueing'. However, in some unusual cases, we may need + // to iterate breaking tokens mutliple times. For example: + // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]' + let mut token_trees: SmallVec<[_; 2]>; + if let TokenTree::Token(token) = &tree { + let mut out = SmallVec::<[_; 2]>::new(); + out.push(token.clone()); + // Iterate to fixpoint: + // * We start off with 'out' containing our initial token, and `temp` empty + // * If we are able to break any tokens in `out`, then `out` will have + // at least one more element than 'temp', so we will try to break tokens + // again. + // * If we cannot break any tokens in 'out', we are done + loop { + let mut temp = SmallVec::<[_; 2]>::new(); + let mut changed = false; + + for token in out.into_iter() { + if let Some((first, second)) = token.kind.break_two_token_op() { + temp.push(Token::new(first, DUMMY_SP)); + temp.push(Token::new(second, DUMMY_SP)); + changed = true; + } else { + temp.push(token); + } + } + out = temp; + if !changed { + break; + } + } + token_trees = out.into_iter().map(|t| TokenTree::Token(t)).collect(); + if token_trees.len() != 1 { + debug!("break_tokens: broke {:?} to {:?}", tree, token_trees); + } + } else { + token_trees = SmallVec::new(); + token_trees.push(tree); + } + token_trees.into_iter() + } + + let mut t1 = self.trees().filter(semantic_tree).flat_map(break_tokens); + let mut t2 = other.trees().filter(semantic_tree).flat_map(break_tokens); + for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { + if !t1.probably_equal_for_proc_macro(&t2) { + return false; + } + } + t1.next().is_none() && t2.next().is_none() + } pub fn map_enumerated TokenTree>(self, mut f: F) -> TokenStream { TokenStream(Lrc::new( diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 8aea8388d08b9..182de85857e5e 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -7,18 +7,16 @@ #![feature(or_patterns)] use rustc_ast::ast; -use rustc_ast::token::{self, Nonterminal, Token, TokenKind, DelimToken}; +use rustc_ast::token::{self, Nonterminal}; use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; -use rustc_span::symbol::kw; use std::path::Path; use std::str; -use std::mem; use log::info; @@ -308,7 +306,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real) { + if tokens.probably_equal_for_proc_macro(&tokens_for_real) { return tokens; } info!( @@ -383,122 +381,3 @@ fn prepend_attrs( builder.push(tokens.clone()); Some(builder.build()) } - -// See comments in `Nonterminal::to_tokenstream` for why we care about -// *probably* equal here rather than actual equality -// -// This is otherwise the same as `eq_unspanned`, only recursing with a -// different method. -pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &TokenStream) -> bool { - // When checking for `probably_eq`, we ignore certain tokens that aren't - // preserved in the AST. Because they are not preserved, the pretty - // printer arbitrarily adds or removes them when printing as token - // streams, making a comparison between a token stream generated from an - // AST and a token stream which was parsed into an AST more reliable. - fn semantic_tree(tree: &TokenTree) -> bool { - if let TokenTree::Token(token) = tree { - if let - // The pretty printer tends to add trailing commas to - // everything, and in particular, after struct fields. - | token::Comma - // The pretty printer emits `NoDelim` as whitespace. - | token::OpenDelim(DelimToken::NoDelim) - | token::CloseDelim(DelimToken::NoDelim) - // The pretty printer collapses many semicolons into one. - | token::Semi - // The pretty printer collapses whitespace arbitrarily and can - // introduce whitespace from `NoDelim`. - | token::Whitespace - // The pretty printer can turn `$crate` into `::crate_name` - | token::ModSep = token.kind { - return false; - } - } - true - } - - let mut t1 = first.trees().filter(semantic_tree); - let mut t2 = other.trees().filter(semantic_tree); - for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2) { - return false; - } - } - t1.next().is_none() && t2.next().is_none() -} - -// See comments in `Nonterminal::to_tokenstream` for why we care about -// *probably* equal here rather than actual equality -crate fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { - use TokenKind::*; - - if mem::discriminant(&first.kind) != mem::discriminant(&other.kind) { - return false; - } - match (&first.kind, &other.kind) { - (&Eq, &Eq) - | (&Lt, &Lt) - | (&Le, &Le) - | (&EqEq, &EqEq) - | (&Ne, &Ne) - | (&Ge, &Ge) - | (&Gt, &Gt) - | (&AndAnd, &AndAnd) - | (&OrOr, &OrOr) - | (&Not, &Not) - | (&Tilde, &Tilde) - | (&At, &At) - | (&Dot, &Dot) - | (&DotDot, &DotDot) - | (&DotDotDot, &DotDotDot) - | (&DotDotEq, &DotDotEq) - | (&Comma, &Comma) - | (&Semi, &Semi) - | (&Colon, &Colon) - | (&ModSep, &ModSep) - | (&RArrow, &RArrow) - | (&LArrow, &LArrow) - | (&FatArrow, &FatArrow) - | (&Pound, &Pound) - | (&Dollar, &Dollar) - | (&Question, &Question) - | (&Whitespace, &Whitespace) - | (&Comment, &Comment) - | (&Eof, &Eof) => true, - - (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b, - - (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b, - - (&DocComment(a), &DocComment(b)) | (&Shebang(a), &Shebang(b)) => a == b, - - (&Literal(a), &Literal(b)) => a == b, - - (&Lifetime(a), &Lifetime(b)) => a == b, - (&Ident(a, b), &Ident(c, d)) => { - b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate) - } - - (&Interpolated(_), &Interpolated(_)) => false, - - _ => panic!("forgot to add a token?"), - } -} - - -// See comments in `Nonterminal::to_tokenstream` for why we care about -// *probably* equal here rather than actual equality -// -// This is otherwise the same as `eq_unspanned`, only recursing with a -// different method. -pub fn tokentree_probably_equal_for_proc_macro(first: &TokenTree, other: &TokenTree) -> bool { - match (first, other) { - (TokenTree::Token(token), TokenTree::Token(token2)) => { - token_probably_equal_for_proc_macro(token, token2) - } - (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2) - } - _ => false, - } -} From 813ce7a688f716e53f3dd22a89ec059af3b67c13 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Wed, 20 May 2020 15:21:24 -0400 Subject: [PATCH 410/695] `SocketAddr(V4|V6)?`::Display now correctly pads its content IpAddr and friends pad when displaying; SocketAddr now does this as well --- src/libstd/net/addr.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 08536de4d55c3..8870c405a2674 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -2,7 +2,7 @@ use crate::cmp::Ordering; use crate::convert::TryInto; use crate::fmt; use crate::hash; -use crate::io; +use crate::io::{self, Write}; use crate::iter; use crate::mem; use crate::net::{htons, ntohs, IpAddr, Ipv4Addr, Ipv6Addr}; @@ -600,7 +600,17 @@ impl fmt::Display for SocketAddr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddrV4 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}:{}", self.ip(), self.port()) + const IPV4_SOCKET_BUF_LEN: usize = 21; + let mut buf = [0; IPV4_SOCKET_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + + // Unwrap is fine because writing to a buffer is infallible + write!(buf_slice, "{}:{}", self.ip(), self.port()).unwrap(); + let len = IPV4_SOCKET_BUF_LEN - buf_slice.len(); + + // This unsafe is OK because we know what is being written to the buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + f.pad(buf) } } @@ -614,7 +624,21 @@ impl fmt::Debug for SocketAddrV4 { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddrV6 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{}]:{}", self.ip(), self.port()) + const IPV6_SOCKET_BUF_LEN: usize = (4 * 8) // The address + + 7 // The colon separators + + 2 // The brackets + + 1 + 5; // The port + + let mut buf = [0; IPV6_SOCKET_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + + // Unwrap is fine because writing to a buffer is infallible + write!(buf_slice, "[{}]:{}", self.ip(), self.port()).unwrap(); + let len = IPV6_SOCKET_BUF_LEN - buf_slice.len(); + + // This unsafe is OK because we know what is being written to the buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + f.pad(buf) } } From defbd845a33cf3c61c3af77aae474964f92e34bb Mon Sep 17 00:00:00 2001 From: Nathan West Date: Wed, 20 May 2020 16:29:36 -0400 Subject: [PATCH 411/695] Added fast-path, tests --- src/libstd/net/addr.rs | 74 ++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 8870c405a2674..2febe157a506d 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -600,17 +600,23 @@ impl fmt::Display for SocketAddr { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddrV4 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const IPV4_SOCKET_BUF_LEN: usize = 21; - let mut buf = [0; IPV4_SOCKET_BUF_LEN]; - let mut buf_slice = &mut buf[..]; - - // Unwrap is fine because writing to a buffer is infallible - write!(buf_slice, "{}:{}", self.ip(), self.port()).unwrap(); - let len = IPV4_SOCKET_BUF_LEN - buf_slice.len(); - - // This unsafe is OK because we know what is being written to the buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - f.pad(buf) + // Fast path: if there's no alignment stuff, write to the output buffer + // directly + if f.precision().is_none() && f.width().is_none() { + write!(f, "{}:{}", self.ip(), self.port()) + } else { + const IPV4_SOCKET_BUF_LEN: usize = 21; + let mut buf = [0; IPV4_SOCKET_BUF_LEN]; + let mut buf_slice = &mut buf[..]; + + // Unwrap is fine because writing to a buffer is infallible + write!(buf_slice, "{}:{}", self.ip(), self.port()).unwrap(); + let len = IPV4_SOCKET_BUF_LEN - buf_slice.len(); + + // This unsafe is OK because we know what is being written to the buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + f.pad(buf) + } } } @@ -624,21 +630,27 @@ impl fmt::Debug for SocketAddrV4 { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for SocketAddrV6 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const IPV6_SOCKET_BUF_LEN: usize = (4 * 8) // The address + // Fast path: if there's no alignment stuff, write to the output + // buffer directly + if f.precision().is_none() && f.width().is_none() { + write!(f, "[{}]:{}", self.ip(), self.port()) + } else { + const IPV6_SOCKET_BUF_LEN: usize = (4 * 8) // The address + 7 // The colon separators + 2 // The brackets + 1 + 5; // The port - let mut buf = [0; IPV6_SOCKET_BUF_LEN]; - let mut buf_slice = &mut buf[..]; + let mut buf = [0; IPV6_SOCKET_BUF_LEN]; + let mut buf_slice = &mut buf[..]; - // Unwrap is fine because writing to a buffer is infallible - write!(buf_slice, "[{}]:{}", self.ip(), self.port()).unwrap(); - let len = IPV6_SOCKET_BUF_LEN - buf_slice.len(); + // Unwrap is fine because writing to a buffer is infallible + write!(buf_slice, "[{}]:{}", self.ip(), self.port()).unwrap(); + let len = IPV6_SOCKET_BUF_LEN - buf_slice.len(); - // This unsafe is OK because we know what is being written to the buffer - let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; - f.pad(buf) + // This unsafe is OK because we know what is being written to the buffer + let buf = unsafe { crate::str::from_utf8_unchecked(&buf[..len]) }; + f.pad(buf) + } } } @@ -1192,6 +1204,28 @@ mod tests { assert!(v6.is_ipv6()); } + #[test] + fn socket_v4_to_str() { + let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); + + assert_eq!(format!("{}", socket), "192.168.0.1:8080"); + assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080 "); + assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080"); + assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 "); + assert_eq!(format!("{:.10}", socket), "192.168.0."); + } + + #[test] + fn socket_v6_to_str() { + let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap(); + + assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::"); + } + #[test] fn compare() { let v4_1 = "224.120.45.1:23456".parse::().unwrap(); From 06a97a027a21f6fe67f91b0630291fbb62d2de83 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Fri, 22 May 2020 15:59:38 -0400 Subject: [PATCH 412/695] Clarify comment message & MAX_LENGTH const --- src/libstd/net/addr.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 2febe157a506d..b780340884e1f 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -605,11 +605,14 @@ impl fmt::Display for SocketAddrV4 { if f.precision().is_none() && f.width().is_none() { write!(f, "{}:{}", self.ip(), self.port()) } else { - const IPV4_SOCKET_BUF_LEN: usize = 21; + const IPV4_SOCKET_BUF_LEN: usize = (3 * 4) // the segments + + 3 // the separators + + 1 + 5; // the port let mut buf = [0; IPV4_SOCKET_BUF_LEN]; let mut buf_slice = &mut buf[..]; - // Unwrap is fine because writing to a buffer is infallible + // Unwrap is fine because writing to a sufficiently-sized + // buffer is infallible write!(buf_slice, "{}:{}", self.ip(), self.port()).unwrap(); let len = IPV4_SOCKET_BUF_LEN - buf_slice.len(); @@ -643,7 +646,8 @@ impl fmt::Display for SocketAddrV6 { let mut buf = [0; IPV6_SOCKET_BUF_LEN]; let mut buf_slice = &mut buf[..]; - // Unwrap is fine because writing to a buffer is infallible + // Unwrap is fine because writing to a sufficiently-sized + // buffer is infallible write!(buf_slice, "[{}]:{}", self.ip(), self.port()).unwrap(); let len = IPV6_SOCKET_BUF_LEN - buf_slice.len(); From b802eebc67e92e100eaebe40c1eb4068c3b2fa2b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 29 May 2020 00:35:02 -0400 Subject: [PATCH 413/695] Fix missing import lost in revert --- src/librustc_parse/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 182de85857e5e..be86b4b7c7720 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -18,7 +18,7 @@ use rustc_span::{FileName, SourceFile, Span}; use std::path::Path; use std::str; -use log::info; +use log::{debug, info}; pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); From 3f3e0ee4b0404eba45c106849ed6eae7104039f6 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 29 May 2020 08:19:58 +0200 Subject: [PATCH 414/695] Add fibersapi feature to winapi in rustc-workspace-hack Co-authored-by: Eric Huss --- src/tools/rustc-workspace-hack/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index cbf7d09f2e42c..1b1f444796654 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -22,6 +22,7 @@ features = [ "basetsd", "consoleapi", "errhandlingapi", + "fibersapi", "ioapiset", "jobapi", "jobapi2", From 12c03db157ced04b5436288781ae0a1728d78e02 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 29 May 2020 11:06:48 +0200 Subject: [PATCH 415/695] Add missing empty line in E0619 explanation --- src/librustc_error_codes/error_codes/E0619.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_error_codes/error_codes/E0619.md b/src/librustc_error_codes/error_codes/E0619.md index 8727692c0a5b8..f516de43095bd 100644 --- a/src/librustc_error_codes/error_codes/E0619.md +++ b/src/librustc_error_codes/error_codes/E0619.md @@ -1,4 +1,5 @@ #### Note: this error code is no longer emitted by the compiler. + The type-checker needed to know the type of an expression, but that type had not yet been inferred. From 283358b081fa2b7e60f3d0d11da1a8e667b13769 Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Fri, 29 May 2020 11:36:50 +0200 Subject: [PATCH 416/695] Update RELEASES.md --- RELEASES.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 132e8a6d94850..510651891b272 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -17,10 +17,13 @@ Compiler -------- - [Rustc now respects the `-C codegen-units` flag in incremental mode.][70156] Additionally when in incremental mode rustc defaults to 256 codegen units. -- [Added tier 3\* support for the `aarch64-unknown-none` and - `aarch64-unknown-none-softfloat` targets.][68334] - [Refactored `catch_unwind`, to have zero-cost unless unwinding is enabled and a panic is thrown.][67502] +- [Added tier 3\* support for the `aarch64-unknown-none` and + `aarch64-unknown-none-softfloat` targets.][68334] +- [Added tier 3 support for `arm64-apple-tvos` and + `x86_64-apple-tvos` targets.][68191] + Libraries --------- @@ -33,6 +36,9 @@ Libraries - [`String` now implements `From<&mut str>`.][69661] - [`IoSlice` now implements `Copy`.][69403] - [`Vec` now implements `From<[T; N]>`.][68692] Where `N` is less than 32. +- [`proc_macro::LexError` now implements `fmt::Display` and `Error`.][68899] +- [`from_le_bytes`, `to_le_bytes`, `from_be_bytes`, and `to_be_bytes` methods are + now `const` for all integer types.][69373] Stabilized APIs --------------- @@ -84,6 +90,9 @@ Compatibility Notes source file rather than the previous format of ``.][70969] **Note:** this may not point a file that actually exists on the user's system. - [The minimum required external LLVM version has been bumped to LLVM 8.][71147] +- [`mem::{zeroed, uninitialised, MaybeUninit}` will now panic when used with types + that do not allow zero initialization such as `NonZeroU8`.][66059] This was + previously a warning. Internal Only ------------- @@ -94,7 +103,10 @@ related tools. - [dep_graph Avoid allocating a set on when the number reads are small.][69778] - [Replace big JS dict with JSON parsing.][71250] - +[69373]: https://github.com/rust-lang/rust/pull/69373/ +[66059]: https://github.com/rust-lang/rust/pull/66059/ +[68191]: https://github.com/rust-lang/rust/pull/68191/ +[68899]: https://github.com/rust-lang/rust/pull/68899/ [71147]: https://github.com/rust-lang/rust/pull/71147/ [71250]: https://github.com/rust-lang/rust/pull/71250/ [70937]: https://github.com/rust-lang/rust/pull/70937/ From 5b37ee1c2ace7b2605848d05b7cc40030ac44167 Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Fri, 29 May 2020 11:45:25 +0200 Subject: [PATCH 417/695] Update RELEASES.md --- RELEASES.md | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 510651891b272..3277f073b1df2 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -9,6 +9,14 @@ Language **Syntax-only changes** - [Expansion-driven outline module parsing][69838] +```rust +#[cfg(FALSE)] +mod foo { + mod bar { + mod baz; // `foo/bar/baz.rs` doesn't exist, but no error! + } +} +``` These are still rejected semantically, so you will likely receive an error but these changes can be seen and parsed by macros and conditional compilation. @@ -53,6 +61,7 @@ Stabilized APIs - [`Layout::align_to`] - [`Layout::pad_to_align`] - [`Layout::array`] +- [`Layout::extend`] Cargo ----- @@ -128,17 +137,18 @@ related tools. [68334]: https://github.com/rust-lang/rust/pull/68334/ [67502]: https://github.com/rust-lang/rust/pull/67502/ [cargo/8062]: https://github.com/rust-lang/cargo/pull/8062/ -[`PathBuf::with_capacity`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.with_capacity -[`PathBuf::capacity`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.capacity -[`PathBuf::clear`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.clear -[`PathBuf::reserve`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.reserve -[`PathBuf::reserve_exact`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.reserve_exact -[`PathBuf::shrink_to_fit`]: https://doc.rust-lang.org/beta/std/path/struct.PathBuf.html#method.shrink_to_fit -[`f32::to_int_unchecked`]: https://doc.rust-lang.org/beta/std/primitive.f32.html#method.to_int_unchecked -[`f64::to_int_unchecked`]: https://doc.rust-lang.org/beta/std/primitive.f64.html#method.to_int_unchecked -[`Layout::align_to`]: https://doc.rust-lang.org/beta/std/alloc/struct.Layout.html#method.align_to -[`Layout::pad_to_align`]: https://doc.rust-lang.org/beta/std/alloc/struct.Layout.html#method.pad_to_align -[`Layout::array`]: https://doc.rust-lang.org/beta/std/alloc/struct.Layout.html#method.array +[`PathBuf::with_capacity`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.with_capacity +[`PathBuf::capacity`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.capacity +[`PathBuf::clear`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.clear +[`PathBuf::reserve`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.reserve +[`PathBuf::reserve_exact`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.reserve_exact +[`PathBuf::shrink_to_fit`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.shrink_to_fit +[`f32::to_int_unchecked`]: https://doc.rust-lang.org/std/primitive.f32.html#method.to_int_unchecked +[`f64::to_int_unchecked`]: https://doc.rust-lang.org/std/primitive.f64.html#method.to_int_unchecked +[`Layout::align_to`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.align_to +[`Layout::pad_to_align`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.pad_to_align +[`Layout::array`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.array +[`Layout::extend`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html#method.extend Version 1.43.1 (2020-05-07) From dbf32e2270f82601bd2816da270ce70269cc59ba Mon Sep 17 00:00:00 2001 From: mendess Date: Fri, 29 May 2020 11:18:15 +0100 Subject: [PATCH 418/695] Remove flaky test and document the other's flakiness --- src/liballoc/tests/boxed.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/liballoc/tests/boxed.rs b/src/liballoc/tests/boxed.rs index c0b8fa665615e..5377485da8f3b 100644 --- a/src/liballoc/tests/boxed.rs +++ b/src/liballoc/tests/boxed.rs @@ -34,6 +34,11 @@ fn box_clone_and_clone_from_equivalence() { } } +/// This test might give a false positive in case the box realocates, but the alocator keeps the +/// original pointer. +/// +/// On the other hand it won't give a false negative, if it fails than the memory was definitly not +/// reused #[test] fn box_clone_from_ptr_stability() { for size in (0..8).map(|i| 2usize.pow(i)) { @@ -43,12 +48,4 @@ fn box_clone_from_ptr_stability() { copy.clone_from(&control); assert_eq!(copy.as_ptr() as usize, copy_raw); } - - for size in (0..8).map(|i| 2usize.pow(i)) { - let control = vec![Dummy { _data: 42 }; size].into_boxed_slice(); - let mut copy = vec![Dummy { _data: 84 }; size + 1].into_boxed_slice(); - let copy_raw = copy.as_ptr() as usize; - copy.clone_from(&control); - assert_ne!(copy.as_ptr() as usize, copy_raw); - } } From 859863dad25cd5cd1ea15422c7b6bd280c6c6327 Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Fri, 29 May 2020 12:49:13 +0200 Subject: [PATCH 419/695] Update RELEASES.md --- RELEASES.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 3277f073b1df2..7ee61c34b7085 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -45,8 +45,9 @@ Libraries - [`IoSlice` now implements `Copy`.][69403] - [`Vec` now implements `From<[T; N]>`.][68692] Where `N` is less than 32. - [`proc_macro::LexError` now implements `fmt::Display` and `Error`.][68899] -- [`from_le_bytes`, `to_le_bytes`, `from_be_bytes`, and `to_be_bytes` methods are - now `const` for all integer types.][69373] +- [`from_le_bytes`, `to_le_bytes`, `from_be_bytes`, `to_be_bytes`, + `from_ne_bytes`, and `to_ne_bytes` methods are now `const` for all + integer types.][69373] Stabilized APIs --------------- From ce722999ea7a150d57504222e16107ef8a6556e6 Mon Sep 17 00:00:00 2001 From: O01eg Date: Fri, 29 May 2020 16:50:03 +0300 Subject: [PATCH 420/695] Fix lld detection if stage0 rustc built with custom libdir --- src/bootstrap/lib.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 15bf831a14835..5328ccb64df7e 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -344,13 +344,19 @@ impl Build { // we always try to use git for LLVM builds let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project")); - let initial_sysroot = config.initial_rustc.parent().unwrap().parent().unwrap(); - let initial_lld = initial_sysroot - .join("lib") - .join("rustlib") - .join(config.build) - .join("bin") - .join("rust-lld"); + let initial_target_libdir = if config.dry_run { + "/dummy/path/to/lib/".to_string() + } else { + output( + Command::new(&config.initial_rustc) + .arg("--target") + .arg(config.build) + .arg("--print") + .arg("target-libdir"), + ) + }; + let initial_lld = + Path::new(&initial_target_libdir).parent().unwrap().join("bin").join("rust-lld"); let mut build = Build { initial_rustc: config.initial_rustc.clone(), From 3f13d97d275c806ea6616071566d8c4f875f18a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 20 May 2020 00:00:00 +0000 Subject: [PATCH 421/695] liveness: Log information about used variables --- src/librustc_passes/liveness.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index ece78d0251281..03ec824366203 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -357,7 +357,7 @@ fn visit_fn<'tcx>( sp: Span, id: hir::HirId, ) { - debug!("visit_fn"); + debug!("visit_fn {:?}", id); // swap in a new set of IR maps for this function body: let def_id = ir.tcx.hir().local_def_id(id); @@ -777,12 +777,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn write_vars(&self, wr: &mut dyn Write, ln: LiveNode, mut test: F) -> io::Result<()> where - F: FnMut(usize) -> LiveNode, + F: FnMut(usize) -> bool, { let node_base_idx = self.idx(ln, Variable(0)); for var_idx in 0..self.ir.num_vars { let idx = node_base_idx + var_idx; - if test(idx).is_valid() { + if test(idx) { write!(wr, " {:?}", Variable(var_idx as u32))?; } } @@ -795,9 +795,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { { let wr = &mut wr as &mut dyn Write; write!(wr, "[ln({:?}) of kind {:?} reads", ln.get(), self.ir.lnk(ln)); - self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx)); + self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_valid()); write!(wr, " writes"); - self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx)); + self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_valid()); + write!(wr, " uses"); + self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx)); + write!(wr, " precedes {:?}]", self.successors[ln.get()]); } String::from_utf8(wr).unwrap() From b3342b4920f2c89e0e41a8c365f576c1d9cdc004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 21 May 2020 00:00:00 +0000 Subject: [PATCH 422/695] liveness: Remove unused clean_exit_var --- src/librustc_passes/liveness.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 03ec824366203..db97445f50b9c 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -85,13 +85,6 @@ //! the function, whether it be by explicit return, panic, or other means. //! //! - `fallthrough_ln`: a live node that represents a fallthrough -//! -//! - `clean_exit_var`: a synthetic variable that is only 'read' from the -//! fallthrough node. It is only live if the function could converge -//! via means other than an explicit `return` expression. That is, it is -//! only dead if the end of the function's block can never be reached. -//! It is the responsibility of typeck to ensure that there are no -//! `return` expressions in a function declared as diverging. use self::LiveNodeKind::*; use self::VarKind::*; @@ -253,7 +246,6 @@ struct LocalInfo { enum VarKind { Param(HirId, Symbol), Local(LocalInfo), - CleanExit, } struct IrMaps<'tcx> { @@ -309,7 +301,6 @@ impl IrMaps<'tcx> { Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) => { self.variable_map.insert(node_id, v); } - CleanExit => {} } debug!("{:?} is {:?}", v, vk); @@ -329,14 +320,13 @@ impl IrMaps<'tcx> { fn variable_name(&self, var: Variable) -> String { match self.var_kinds[var.get()] { Local(LocalInfo { name, .. }) | Param(_, name) => name.to_string(), - CleanExit => "".to_owned(), } } fn variable_is_shorthand(&self, var: Variable) -> bool { match self.var_kinds[var.get()] { Local(LocalInfo { is_shorthand, .. }) => is_shorthand, - Param(..) | CleanExit => false, + Param(..) => false, } } @@ -649,7 +639,6 @@ impl RWUTable { struct Specials { exit_ln: LiveNode, fallthrough_ln: LiveNode, - clean_exit_var: Variable, } const ACC_READ: u32 = 1; @@ -680,7 +669,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let specials = Specials { exit_ln: ir.add_live_node(ExitNode), fallthrough_ln: ir.add_live_node(ExitNode), - clean_exit_var: ir.add_variable(CleanExit), }; let tables = ir.tcx.typeck_tables_of(def_id); @@ -913,7 +901,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // explicitly return: let s = self.s; self.init_from_succ(s.fallthrough_ln, s.exit_ln); - self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); let entry_ln = self.propagate_through_expr(body, s.fallthrough_ln); From 7c6301496bbc5d1531369e94a17450c9ad0bbbe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 21 May 2020 00:00:00 +0000 Subject: [PATCH 423/695] liveness: Remove unused fallthrough_ln --- src/librustc_passes/liveness.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index db97445f50b9c..33ee08aebc31f 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -83,8 +83,6 @@ //! //! - `exit_ln`: a live node that is generated to represent every 'exit' from //! the function, whether it be by explicit return, panic, or other means. -//! -//! - `fallthrough_ln`: a live node that represents a fallthrough use self::LiveNodeKind::*; use self::VarKind::*; @@ -638,7 +636,6 @@ impl RWUTable { #[derive(Copy, Clone)] struct Specials { exit_ln: LiveNode, - fallthrough_ln: LiveNode, } const ACC_READ: u32 = 1; @@ -668,7 +665,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // an implicit return let specials = Specials { exit_ln: ir.add_live_node(ExitNode), - fallthrough_ln: ir.add_live_node(ExitNode), }; let tables = ir.tcx.typeck_tables_of(def_id); @@ -897,12 +893,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn compute(&mut self, body: &hir::Expr<'_>) -> LiveNode { debug!("compute: using id for body, {:?}", body); - // the fallthrough exit is only for those cases where we do not - // explicitly return: let s = self.s; - self.init_from_succ(s.fallthrough_ln, s.exit_ln); - - let entry_ln = self.propagate_through_expr(body, s.fallthrough_ln); + let entry_ln = self.propagate_through_expr(body, s.exit_ln); // hack to skip the loop unless debug! is enabled: debug!( From 74fcbfb49149c07ad9beea0ddd47d11b125e0e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 21 May 2020 00:00:00 +0000 Subject: [PATCH 424/695] liveness: Include upvars in the analysis --- src/librustc_passes/liveness.rs | 69 ++++++++++++++++----------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 33ee08aebc31f..00dc8a41350b3 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -244,6 +244,7 @@ struct LocalInfo { enum VarKind { Param(HirId, Symbol), Local(LocalInfo), + Upvar(HirId, Symbol), } struct IrMaps<'tcx> { @@ -296,7 +297,7 @@ impl IrMaps<'tcx> { self.num_vars += 1; match vk { - Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) => { + Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) | Upvar(node_id, _) => { self.variable_map.insert(node_id, v); } } @@ -317,14 +318,14 @@ impl IrMaps<'tcx> { fn variable_name(&self, var: Variable) -> String { match self.var_kinds[var.get()] { - Local(LocalInfo { name, .. }) | Param(_, name) => name.to_string(), + Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name.to_string(), } } fn variable_is_shorthand(&self, var: Variable) -> bool { match self.var_kinds[var.get()] { Local(LocalInfo { is_shorthand, .. }) => is_shorthand, - Param(..) => false, + Param(..) | Upvar(..) => false, } } @@ -365,6 +366,14 @@ fn visit_fn<'tcx>( let body = ir.tcx.hir().body(body_id); + if let Some(upvars) = ir.tcx.upvars_mentioned(def_id) { + for (&var_hir_id, _upvar) in upvars { + debug!("adding upvar {:?}", var_hir_id); + let var_name = ir.tcx.hir().name(var_hir_id); + fn_maps.add_variable(Upvar(var_hir_id, var_name)); + } + } + for param in body.params { let is_shorthand = match param.pat.kind { rustc_hir::PatKind::Struct(..) => true, @@ -450,11 +459,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { // live nodes required for uses or definitions of variables: hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); - if let Res::Local(var_hir_id) = path.res { - let upvars = ir.tcx.upvars_mentioned(ir.body_owner); - if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hir_id)) { - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); - } + if let Res::Local(_var_hir_id) = path.res { + ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); } intravisit::walk_expr(ir, expr); } @@ -470,16 +476,9 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { let mut call_caps = Vec::new(); let closure_def_id = ir.tcx.hir().local_def_id(expr.hir_id); if let Some(upvars) = ir.tcx.upvars_mentioned(closure_def_id) { - let parent_upvars = ir.tcx.upvars_mentioned(ir.body_owner); - call_caps.extend(upvars.iter().filter_map(|(&var_id, upvar)| { - let has_parent = - parent_upvars.map_or(false, |upvars| upvars.contains_key(&var_id)); - if !has_parent { - let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); - Some(CaptureInfo { ln: upvar_ln, var_hid: var_id }) - } else { - None - } + call_caps.extend(upvars.iter().map(|(&var_id, upvar)| { + let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); + CaptureInfo { ln: upvar_ln, var_hid: var_id } })); } ir.set_captures(expr.hir_id, call_caps); @@ -894,6 +893,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!("compute: using id for body, {:?}", body); let s = self.s; + + if let Some(upvars) = self.ir.tcx.upvars_mentioned(self.ir.body_owner) { + for (&var_hir_id, upvar) in upvars.iter().rev() { + let var = self.variable(var_hir_id, upvar.span); + self.acc(s.exit_ln, var, ACC_READ | ACC_USE); + } + } + let entry_ln = self.propagate_through_expr(body, s.exit_ln); // hack to skip the loop unless debug! is enabled: @@ -1345,14 +1352,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { acc: u32, ) -> LiveNode { match path.res { - Res::Local(hid) => { - let upvars = self.ir.tcx.upvars_mentioned(self.ir.body_owner); - if !upvars.map_or(false, |upvars| upvars.contains_key(&hid)) { - self.access_var(hir_id, hid, succ, acc, path.span) - } else { - succ - } - } + Res::Local(hid) => self.access_var(hir_id, hid, succ, acc, path.span), _ => succ, } } @@ -1511,16 +1511,13 @@ impl<'tcx> Liveness<'_, 'tcx> { match expr.kind { hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { if let Res::Local(var_hid) = path.res { - let upvars = self.ir.tcx.upvars_mentioned(self.ir.body_owner); - if !upvars.map_or(false, |upvars| upvars.contains_key(&var_hid)) { - // Assignment to an immutable variable or argument: only legal - // if there is no later assignment. If this local is actually - // mutable, then check for a reassignment to flag the mutability - // as being used. - let ln = self.live_node(expr.hir_id, expr.span); - let var = self.variable(var_hid, expr.span); - self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var); - } + // Assignment to an immutable variable or argument: only legal + // if there is no later assignment. If this local is actually + // mutable, then check for a reassignment to flag the mutability + // as being used. + let ln = self.live_node(expr.hir_id, expr.span); + let var = self.variable(var_hid, expr.span); + self.warn_about_dead_assign(vec![expr.span], expr.hir_id, ln, var); } } _ => { From 4dc56614b27337fe770943760f41a58bbab7c7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Fri, 22 May 2020 00:00:00 +0000 Subject: [PATCH 425/695] liveness: Warn about unused captured variables --- src/librustc_passes/liveness.rs | 224 +++++++++++++----- .../closure-immutable-outer-variable.fixed | 2 +- .../closure-immutable-outer-variable.rs | 2 +- .../closure-immutable-outer-variable.stderr | 4 +- src/test/ui/issues/issue-11958.rs | 3 +- src/test/ui/issues/issue-11958.stderr | 20 ++ src/test/ui/liveness/liveness-upvars.rs | 108 +++++++++ src/test/ui/liveness/liveness-upvars.stderr | 150 ++++++++++++ .../unboxed-closures-counter-not-moved.rs | 6 +- .../unboxed-closures-counter-not-moved.stderr | 27 +++ .../unboxed-closures-move-mutable.rs | 4 +- .../unboxed-closures-move-mutable.stderr | 19 ++ 12 files changed, 505 insertions(+), 64 deletions(-) create mode 100644 src/test/ui/issues/issue-11958.stderr create mode 100644 src/test/ui/liveness/liveness-upvars.rs create mode 100644 src/test/ui/liveness/liveness-upvars.stderr create mode 100644 src/test/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr create mode 100644 src/test/ui/unboxed-closures/unboxed-closures-move-mutable.stderr diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 00dc8a41350b3..55978afc59437 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -76,13 +76,10 @@ //! is not just used to generate a new value. For example, `x += 1` is //! a read but not a use. This is used to generate better warnings. //! -//! ## Special Variables +//! ## Special nodes and variables //! -//! We generate various special variables for various, well, special purposes. -//! These are described in the `specials` struct: -//! -//! - `exit_ln`: a live node that is generated to represent every 'exit' from -//! the function, whether it be by explicit return, panic, or other means. +//! We generate various special nodes for various, well, special purposes. +//! These are described in the `Specials` struct. use self::LiveNodeKind::*; use self::VarKind::*; @@ -131,6 +128,7 @@ enum LiveNodeKind { UpvarNode(Span), ExprNode(Span), VarDefNode(Span), + ClosureNode, ExitNode, } @@ -140,6 +138,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { UpvarNode(s) => format!("Upvar node [{}]", sm.span_to_string(s)), ExprNode(s) => format!("Expr node [{}]", sm.span_to_string(s)), VarDefNode(s) => format!("Var def node [{}]", sm.span_to_string(s)), + ClosureNode => "Closure node".to_owned(), ExitNode => "Exit node".to_owned(), } } @@ -396,10 +395,12 @@ fn visit_fn<'tcx>( // compute liveness let mut lsets = Liveness::new(&mut fn_maps, def_id); - let entry_ln = lsets.compute(&body.value); + let entry_ln = lsets.compute(fk, &body, sp, id); + lsets.log_liveness(entry_ln, id); // check for various error conditions lsets.visit_body(body); + lsets.warn_about_unused_upvars(entry_ln); lsets.warn_about_unused_args(body, entry_ln); } @@ -634,6 +635,12 @@ impl RWUTable { #[derive(Copy, Clone)] struct Specials { + /// A live node representing a point of execution before closure entry & + /// after closure exit. Used to calculate liveness of captured variables + /// through calls to the same closure. Used for Fn & FnMut closures only. + closure_ln: LiveNode, + /// A live node representing every 'exit' from the function, whether it be + /// by explicit return, panic, or other means. exit_ln: LiveNode, } @@ -658,11 +665,8 @@ struct Liveness<'a, 'tcx> { impl<'a, 'tcx> Liveness<'a, 'tcx> { fn new(ir: &'a mut IrMaps<'tcx>, def_id: LocalDefId) -> Liveness<'a, 'tcx> { - // Special nodes and variables: - // - exit_ln represents the end of the fn, either by return or panic - // - implicit_ret_var is a pseudo-variable that represents - // an implicit return let specials = Specials { + closure_ln: ir.add_live_node(ClosureNode), exit_ln: ir.add_live_node(ExitNode), }; @@ -789,6 +793,20 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { String::from_utf8(wr).unwrap() } + fn log_liveness(&self, entry_ln: LiveNode, hir_id: hir::HirId) { + // hack to skip the loop unless debug! is enabled: + debug!( + "^^ liveness computation results for body {} (entry={:?})", + { + for ln_idx in 0..self.ir.num_live_nodes { + debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32))); + } + hir_id + }, + entry_ln + ); + } + fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) { self.successors[ln.get()] = succ_ln; @@ -889,33 +907,87 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.rwu_table.assign_unpacked(idx, rwu); } - fn compute(&mut self, body: &hir::Expr<'_>) -> LiveNode { - debug!("compute: using id for body, {:?}", body); + fn compute( + &mut self, + fk: FnKind<'_>, + body: &hir::Body<'_>, + span: Span, + id: hir::HirId, + ) -> LiveNode { + debug!("compute: using id for body, {:?}", body.value); - let s = self.s; + // # Liveness of captured variables + // + // When computing the liveness for captured variables we take into + // account how variable is captured (ByRef vs ByValue) and what is the + // closure kind (Generator / FnOnce vs Fn / FnMut). + // + // Variables captured by reference are assumed to be used on the exit + // from the closure. + // + // In FnOnce closures, variables captured by value are known to be dead + // on exit since it is impossible to call the closure again. + // + // In Fn / FnMut closures, variables captured by value are live on exit + // if they are live on the entry to the closure, since only the closure + // itself can access them on subsequent calls. if let Some(upvars) = self.ir.tcx.upvars_mentioned(self.ir.body_owner) { + // Mark upvars captured by reference as used after closure exits. for (&var_hir_id, upvar) in upvars.iter().rev() { - let var = self.variable(var_hir_id, upvar.span); - self.acc(s.exit_ln, var, ACC_READ | ACC_USE); + let upvar_id = ty::UpvarId { + var_path: ty::UpvarPath { hir_id: var_hir_id }, + closure_expr_id: self.ir.body_owner.expect_local(), + }; + match self.tables.upvar_capture(upvar_id) { + ty::UpvarCapture::ByRef(_) => { + let var = self.variable(var_hir_id, upvar.span); + self.acc(self.s.exit_ln, var, ACC_READ | ACC_USE); + } + ty::UpvarCapture::ByValue => {} + } } } - let entry_ln = self.propagate_through_expr(body, s.exit_ln); + let succ = self.propagate_through_expr(&body.value, self.s.exit_ln); - // hack to skip the loop unless debug! is enabled: - debug!( - "^^ liveness computation results for body {} (entry={:?})", - { - for ln_idx in 0..self.ir.num_live_nodes { - debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32))); - } - body.hir_id + match fk { + FnKind::Method(..) | FnKind::ItemFn(..) => return succ, + FnKind::Closure(..) => {} + } + + let ty = self.tables.node_type(id); + match ty.kind { + ty::Closure(_def_id, substs) => match substs.as_closure().kind() { + ty::ClosureKind::Fn => {} + ty::ClosureKind::FnMut => {} + ty::ClosureKind::FnOnce => return succ, }, - entry_ln - ); + ty::Generator(..) => return succ, + _ => { + span_bug!(span, "type of closure expr {:?} is not a closure {:?}", id, ty,); + } + }; - entry_ln + // Propagate through calls to the closure. + let mut first_merge = true; + loop { + self.init_from_succ(self.s.closure_ln, succ); + for param in body.params { + param.pat.each_binding(|_bm, hir_id, _x, ident| { + let var = self.variable(hir_id, ident.span); + self.define(self.s.closure_ln, var); + }) + } + + if !self.merge_from_succ(self.s.exit_ln, self.s.closure_ln, first_merge) { + break; + } + first_merge = false; + assert_eq!(succ, self.propagate_through_expr(&body.value, self.s.exit_ln)); + } + + succ } fn propagate_through_block(&mut self, blk: &hir::Block<'_>, succ: LiveNode) -> LiveNode { @@ -1533,11 +1605,60 @@ impl<'tcx> Liveness<'_, 'tcx> { if name.is_empty() || name.as_bytes()[0] == b'_' { None } else { Some(name) } } + fn warn_about_unused_upvars(&self, entry_ln: LiveNode) { + let upvars = match self.ir.tcx.upvars_mentioned(self.ir.body_owner) { + None => return, + Some(upvars) => upvars, + }; + for (&var_hir_id, upvar) in upvars.iter() { + let var = self.variable(var_hir_id, upvar.span); + let upvar_id = ty::UpvarId { + var_path: ty::UpvarPath { hir_id: var_hir_id }, + closure_expr_id: self.ir.body_owner.expect_local(), + }; + match self.tables.upvar_capture(upvar_id) { + ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByRef(..) => continue, + }; + if self.used_on_entry(entry_ln, var) { + if self.live_on_entry(entry_ln, var).is_none() { + if let Some(name) = self.should_warn(var) { + self.ir.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_ASSIGNMENTS, + var_hir_id, + vec![upvar.span], + |lint| { + lint.build(&format!("value captured by `{}` is never read", name)) + .help("did you mean to capture by reference instead?") + .emit(); + }, + ); + } + } + } else { + if let Some(name) = self.should_warn(var) { + self.ir.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_VARIABLES, + var_hir_id, + vec![upvar.span], + |lint| { + lint.build(&format!("unused variable: `{}`", name)) + .help("did you mean to capture by reference instead?") + .emit(); + }, + ); + } + } + } + } + fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) { for p in body.params { self.check_unused_vars_in_pat(&p.pat, Some(entry_ln), |spans, hir_id, ln, var| { if self.live_on_entry(ln, var).is_none() { - self.report_dead_assign(hir_id, spans, var, true); + self.report_unsed_assign(hir_id, spans, var, |name| { + format!("value passed to `{}` is never read", name) + }); } }); } @@ -1651,35 +1772,30 @@ impl<'tcx> Liveness<'_, 'tcx> { fn warn_about_dead_assign(&self, spans: Vec, hir_id: HirId, ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { - self.report_dead_assign(hir_id, spans, var, false); + self.report_unsed_assign(hir_id, spans, var, |name| { + format!("value assigned to `{}` is never read", name) + }); } } - fn report_dead_assign(&self, hir_id: HirId, spans: Vec, var: Variable, is_param: bool) { + fn report_unsed_assign( + &self, + hir_id: HirId, + spans: Vec, + var: Variable, + message: impl Fn(&str) -> String, + ) { if let Some(name) = self.should_warn(var) { - if is_param { - self.ir.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_ASSIGNMENTS, - hir_id, - spans, - |lint| { - lint.build(&format!("value passed to `{}` is never read", name)) - .help("maybe it is overwritten before being read?") - .emit(); - }, - ) - } else { - self.ir.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_ASSIGNMENTS, - hir_id, - spans, - |lint| { - lint.build(&format!("value assigned to `{}` is never read", name)) - .help("maybe it is overwritten before being read?") - .emit(); - }, - ) - } + self.ir.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_ASSIGNMENTS, + hir_id, + spans, + |lint| { + lint.build(&message(&name)) + .help("maybe it is overwritten before being read?") + .emit(); + }, + ) } } } diff --git a/src/test/ui/closures/closure-immutable-outer-variable.fixed b/src/test/ui/closures/closure-immutable-outer-variable.fixed index 102f1f94a36e1..1b0feede34ecf 100644 --- a/src/test/ui/closures/closure-immutable-outer-variable.fixed +++ b/src/test/ui/closures/closure-immutable-outer-variable.fixed @@ -8,6 +8,6 @@ fn foo(mut f: Box) { fn main() { let mut y = true; - foo(Box::new(move || y = false) as Box<_>); + foo(Box::new(move || y = !y) as Box<_>); //~^ ERROR cannot assign to `y`, as it is not declared as mutable } diff --git a/src/test/ui/closures/closure-immutable-outer-variable.rs b/src/test/ui/closures/closure-immutable-outer-variable.rs index 6eb43b372c96c..50ec1c6148a04 100644 --- a/src/test/ui/closures/closure-immutable-outer-variable.rs +++ b/src/test/ui/closures/closure-immutable-outer-variable.rs @@ -8,6 +8,6 @@ fn foo(mut f: Box) { fn main() { let y = true; - foo(Box::new(move || y = false) as Box<_>); + foo(Box::new(move || y = !y) as Box<_>); //~^ ERROR cannot assign to `y`, as it is not declared as mutable } diff --git a/src/test/ui/closures/closure-immutable-outer-variable.stderr b/src/test/ui/closures/closure-immutable-outer-variable.stderr index 7e60f3cd8ffa4..799097889cd30 100644 --- a/src/test/ui/closures/closure-immutable-outer-variable.stderr +++ b/src/test/ui/closures/closure-immutable-outer-variable.stderr @@ -3,8 +3,8 @@ error[E0594]: cannot assign to `y`, as it is not declared as mutable | LL | let y = true; | - help: consider changing this to be mutable: `mut y` -LL | foo(Box::new(move || y = false) as Box<_>); - | ^^^^^^^^^ cannot assign +LL | foo(Box::new(move || y = !y) as Box<_>); + | ^^^^^^ cannot assign error: aborting due to previous error diff --git a/src/test/ui/issues/issue-11958.rs b/src/test/ui/issues/issue-11958.rs index 8fe8a8c606189..a7af01e25b4e2 100644 --- a/src/test/ui/issues/issue-11958.rs +++ b/src/test/ui/issues/issue-11958.rs @@ -1,5 +1,4 @@ // run-pass -#![forbid(warnings)] // We shouldn't need to rebind a moved upvar as mut if it's already // marked as mut @@ -7,4 +6,6 @@ pub fn main() { let mut x = 1; let _thunk = Box::new(move|| { x = 2; }); + //~^ WARN value assigned to `x` is never read + //~| WARN unused variable: `x` } diff --git a/src/test/ui/issues/issue-11958.stderr b/src/test/ui/issues/issue-11958.stderr new file mode 100644 index 0000000000000..25de6ff4c118c --- /dev/null +++ b/src/test/ui/issues/issue-11958.stderr @@ -0,0 +1,20 @@ +warning: value assigned to `x` is never read + --> $DIR/issue-11958.rs:8:36 + | +LL | let _thunk = Box::new(move|| { x = 2; }); + | ^ + | + = note: `#[warn(unused_assignments)]` on by default + = help: maybe it is overwritten before being read? + +warning: unused variable: `x` + --> $DIR/issue-11958.rs:8:36 + | +LL | let _thunk = Box::new(move|| { x = 2; }); + | ^ + | + = note: `#[warn(unused_variables)]` on by default + = help: did you mean to capture by reference instead? + +warning: 2 warnings emitted + diff --git a/src/test/ui/liveness/liveness-upvars.rs b/src/test/ui/liveness/liveness-upvars.rs new file mode 100644 index 0000000000000..b2837e74b8c51 --- /dev/null +++ b/src/test/ui/liveness/liveness-upvars.rs @@ -0,0 +1,108 @@ +// edition:2018 +// check-pass +#![warn(unused)] +#![allow(unreachable_code)] + +pub fn unintentional_copy_one() { + let mut last = None; + let mut f = move |s| { + last = Some(s); //~ WARN value assigned to `last` is never read + //~| WARN unused variable: `last` + }; + f("a"); + f("b"); + f("c"); + dbg!(last.unwrap()); +} + +pub fn unintentional_copy_two() { + let mut sum = 0; + (1..10).for_each(move |x| { + sum += x; //~ WARN unused variable: `sum` + }); + dbg!(sum); +} + +pub fn f() { + let mut c = 0; + + // Captured by value, but variable is dead on entry. + move || { + c = 1; //~ WARN value captured by `c` is never read + println!("{}", c); + }; + let _ = async move { + c = 1; //~ WARN value captured by `c` is never read + println!("{}", c); + }; + + // Read and written to, but never actually used. + move || { + c += 1; //~ WARN unused variable: `c` + }; + let _ = async move { + c += 1; //~ WARN value assigned to `c` is never read + //~| WARN unused variable: `c` + }; + + move || { + println!("{}", c); + // Value is read by closure itself on later invocations. + c += 1; + }; + let b = Box::new(42); + move || { + println!("{}", c); + // Never read because this is FnOnce closure. + c += 1; //~ WARN value assigned to `c` is never read + drop(b); + }; + let _ = async move { + println!("{}", c); + // Never read because this is a generator. + c += 1; //~ WARN value assigned to `c` is never read + }; +} + +pub fn nested() { + let mut d = None; + let mut e = None; + || { + || { + d = Some("d1"); //~ WARN value assigned to `d` is never read + d = Some("d2"); + }; + move || { + e = Some("e1"); //~ WARN value assigned to `e` is never read + //~| WARN unused variable: `e` + e = Some("e2"); //~ WARN value assigned to `e` is never read + }; + }; +} + +pub fn g(mut v: T) { + |r| { + if r { + v = T::default(); //~ WARN value assigned to `v` is never read + } else { + drop(v); + } + }; +} + +pub fn h() { + let mut z = T::default(); + move |b| { + loop { + if b { + z = T::default(); //~ WARN value assigned to `z` is never read + //~| WARN unused variable: `z` + } else { + return; + } + } + dbg!(z); + }; +} + +fn main() {} diff --git a/src/test/ui/liveness/liveness-upvars.stderr b/src/test/ui/liveness/liveness-upvars.stderr new file mode 100644 index 0000000000000..14fed91786436 --- /dev/null +++ b/src/test/ui/liveness/liveness-upvars.stderr @@ -0,0 +1,150 @@ +warning: value assigned to `last` is never read + --> $DIR/liveness-upvars.rs:9:9 + | +LL | last = Some(s); + | ^^^^ + | +note: the lint level is defined here + --> $DIR/liveness-upvars.rs:3:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]` + = help: maybe it is overwritten before being read? + +warning: unused variable: `last` + --> $DIR/liveness-upvars.rs:9:9 + | +LL | last = Some(s); + | ^^^^ + | +note: the lint level is defined here + --> $DIR/liveness-upvars.rs:3:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + = help: did you mean to capture by reference instead? + +warning: unused variable: `sum` + --> $DIR/liveness-upvars.rs:21:9 + | +LL | sum += x; + | ^^^ + | + = help: did you mean to capture by reference instead? + +warning: value captured by `c` is never read + --> $DIR/liveness-upvars.rs:31:9 + | +LL | c = 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value captured by `c` is never read + --> $DIR/liveness-upvars.rs:35:9 + | +LL | c = 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: unused variable: `c` + --> $DIR/liveness-upvars.rs:41:9 + | +LL | c += 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value assigned to `c` is never read + --> $DIR/liveness-upvars.rs:44:9 + | +LL | c += 1; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `c` + --> $DIR/liveness-upvars.rs:44:9 + | +LL | c += 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value assigned to `c` is never read + --> $DIR/liveness-upvars.rs:57:9 + | +LL | c += 1; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `c` is never read + --> $DIR/liveness-upvars.rs:63:9 + | +LL | c += 1; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `d` is never read + --> $DIR/liveness-upvars.rs:72:13 + | +LL | d = Some("d1"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `e` is never read + --> $DIR/liveness-upvars.rs:76:13 + | +LL | e = Some("e1"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `e` is never read + --> $DIR/liveness-upvars.rs:78:13 + | +LL | e = Some("e2"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `e` + --> $DIR/liveness-upvars.rs:76:13 + | +LL | e = Some("e1"); + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value assigned to `v` is never read + --> $DIR/liveness-upvars.rs:86:13 + | +LL | v = T::default(); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `z` is never read + --> $DIR/liveness-upvars.rs:98:17 + | +LL | z = T::default(); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `z` + --> $DIR/liveness-upvars.rs:98:17 + | +LL | z = T::default(); + | ^ + | + = help: did you mean to capture by reference instead? + +warning: 17 warnings emitted + diff --git a/src/test/ui/unboxed-closures/unboxed-closures-counter-not-moved.rs b/src/test/ui/unboxed-closures/unboxed-closures-counter-not-moved.rs index fb24df3c24e87..390386e57fa72 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-counter-not-moved.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-counter-not-moved.rs @@ -1,5 +1,4 @@ // run-pass -#![allow(unused_variables)] // Test that we mutate a counter on the stack only when we expect to. fn call(f: F) where F : FnOnce() { @@ -13,7 +12,7 @@ fn main() { call(|| { // Move `y`, but do not move `counter`, even though it is read // by value (note that it is also mutated). - for item in y { + for item in y { //~ WARN unused variable: `item` let v = counter; counter += v; } @@ -22,7 +21,8 @@ fn main() { call(move || { // this mutates a moved copy, and hence doesn't affect original - counter += 1; + counter += 1; //~ WARN value assigned to `counter` is never read + //~| WARN unused variable: `counter` }); assert_eq!(counter, 88); } diff --git a/src/test/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr b/src/test/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr new file mode 100644 index 0000000000000..ba4b3dac6705e --- /dev/null +++ b/src/test/ui/unboxed-closures/unboxed-closures-counter-not-moved.stderr @@ -0,0 +1,27 @@ +warning: unused variable: `item` + --> $DIR/unboxed-closures-counter-not-moved.rs:15:13 + | +LL | for item in y { + | ^^^^ help: if this is intentional, prefix it with an underscore: `_item` + | + = note: `#[warn(unused_variables)]` on by default + +warning: value assigned to `counter` is never read + --> $DIR/unboxed-closures-counter-not-moved.rs:24:9 + | +LL | counter += 1; + | ^^^^^^^ + | + = note: `#[warn(unused_assignments)]` on by default + = help: maybe it is overwritten before being read? + +warning: unused variable: `counter` + --> $DIR/unboxed-closures-counter-not-moved.rs:24:9 + | +LL | counter += 1; + | ^^^^^^^ + | + = help: did you mean to capture by reference instead? + +warning: 3 warnings emitted + diff --git a/src/test/ui/unboxed-closures/unboxed-closures-move-mutable.rs b/src/test/ui/unboxed-closures/unboxed-closures-move-mutable.rs index 9b519e63a95cc..e5b19db782231 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-move-mutable.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-move-mutable.rs @@ -13,11 +13,11 @@ fn set(x: &mut usize) { *x = 42; } fn main() { { let mut x = 0_usize; - move || x += 1; + move || x += 1; //~ WARN unused variable: `x` } { let mut x = 0_usize; - move || x += 1; + move || x += 1; //~ WARN unused variable: `x` } { let mut x = 0_usize; diff --git a/src/test/ui/unboxed-closures/unboxed-closures-move-mutable.stderr b/src/test/ui/unboxed-closures/unboxed-closures-move-mutable.stderr new file mode 100644 index 0000000000000..4dfd1bb307574 --- /dev/null +++ b/src/test/ui/unboxed-closures/unboxed-closures-move-mutable.stderr @@ -0,0 +1,19 @@ +warning: unused variable: `x` + --> $DIR/unboxed-closures-move-mutable.rs:16:17 + | +LL | move || x += 1; + | ^ + | + = note: `#[warn(unused_variables)]` on by default + = help: did you mean to capture by reference instead? + +warning: unused variable: `x` + --> $DIR/unboxed-closures-move-mutable.rs:20:17 + | +LL | move || x += 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: 2 warnings emitted + From c0ac2e86f9d7545594fdb1be27f2fe9336699ca7 Mon Sep 17 00:00:00 2001 From: O01eg Date: Fri, 29 May 2020 10:15:46 +0300 Subject: [PATCH 426/695] Get libdir from stage0 compiler --- src/bootstrap/builder.rs | 1 + src/bootstrap/lib.rs | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 5489b1bc66b64..c8a85eae252ff 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -648,6 +648,7 @@ impl<'a> Builder<'a> { pub fn sysroot_libdir_relative(&self, compiler: Compiler) -> &Path { match self.config.libdir_relative() { Some(relative_libdir) if compiler.stage >= 1 => relative_libdir, + _ if compiler.stage == 0 => &self.build.initial_libdir, _ => Path::new("lib"), } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 5328ccb64df7e..c46c68e4d5682 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -243,6 +243,7 @@ pub struct Build { initial_rustc: PathBuf, initial_cargo: PathBuf, initial_lld: PathBuf, + initial_libdir: PathBuf, // Runtime state filled in later on // C/C++ compilers and archiver for all targets @@ -344,8 +345,8 @@ impl Build { // we always try to use git for LLVM builds let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project")); - let initial_target_libdir = if config.dry_run { - "/dummy/path/to/lib/".to_string() + let initial_target_libdir_str = if config.dry_run { + "/dummy/lib/path/to/lib/".to_string() } else { output( Command::new(&config.initial_rustc) @@ -355,13 +356,28 @@ impl Build { .arg("target-libdir"), ) }; - let initial_lld = - Path::new(&initial_target_libdir).parent().unwrap().join("bin").join("rust-lld"); + let initial_target_dir = Path::new(&initial_target_libdir_str).parent().unwrap(); + let initial_lld = initial_target_dir.join("bin").join("rust-lld"); + + let initial_sysroot = if config.dry_run { + "/dummy".to_string() + } else { + output(Command::new(&config.initial_rustc).arg("--print").arg("sysroot")) + }; + let initial_libdir = initial_target_dir + .parent() + .unwrap() + .parent() + .unwrap() + .strip_prefix(initial_sysroot.trim()) + .unwrap() + .to_path_buf(); let mut build = Build { initial_rustc: config.initial_rustc.clone(), initial_cargo: config.initial_cargo.clone(), initial_lld, + initial_libdir, local_rebuild: config.local_rebuild, fail_fast: config.cmd.fail_fast(), doc_tests: config.cmd.doc_tests(), From b78b15665b622cc37b25e9bd971537296403b83d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 26 May 2020 20:07:59 +0100 Subject: [PATCH 427/695] Improve inline asm error diagnostics --- src/libfmt_macros/lib.rs | 24 +++++- src/librustc_ast/ast.rs | 3 +- src/librustc_ast_lowering/expr.rs | 3 +- src/librustc_builtin_macros/asm.rs | 10 ++- src/librustc_codegen_llvm/asm.rs | 32 ++++++-- src/librustc_codegen_llvm/back/write.rs | 51 +++++++++++-- src/librustc_codegen_llvm/llvm/ffi.rs | 9 ++- src/librustc_codegen_ssa/back/write.rs | 39 ++++++++-- src/librustc_codegen_ssa/mir/block.rs | 12 ++- src/librustc_codegen_ssa/traits/asm.rs | 2 +- src/librustc_hir/hir.rs | 1 + src/librustc_middle/mir/mod.rs | 6 +- src/librustc_middle/mir/type_foldable.rs | 10 ++- src/librustc_middle/mir/visit.rs | 1 + src/librustc_mir/borrow_check/invalidation.rs | 8 +- src/librustc_mir/borrow_check/mod.rs | 8 +- .../dataflow/framework/direction.rs | 2 +- .../dataflow/move_paths/builder.rs | 8 +- src/librustc_mir_build/build/expr/into.rs | 3 +- src/librustc_mir_build/hair/cx/expr.rs | 1 + src/librustc_mir_build/hair/mod.rs | 1 + src/librustc_span/lib.rs | 12 ++- src/rustllvm/RustWrapper.cpp | 31 +++++++- src/test/ui/asm/srcloc.rs | 41 ++++++++++ src/test/ui/asm/srcloc.stderr | 74 +++++++++++++++++++ src/test/ui/issues/issue-23458.stderr | 15 ++-- src/test/ui/llvm-asm/issue-69092.rs | 2 +- src/test/ui/llvm-asm/issue-69092.stderr | 13 ++-- 28 files changed, 365 insertions(+), 57 deletions(-) create mode 100644 src/test/ui/asm/srcloc.rs create mode 100644 src/test/ui/asm/srcloc.stderr diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 677c027f17b54..23bf7b35419db 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -191,6 +191,11 @@ pub struct Parser<'a> { append_newline: bool, /// Whether this formatting string is a literal or it comes from a macro. is_literal: bool, + /// Start position of the current line. + cur_line_start: usize, + /// Start and end byte offset of every line of the format string. Excludes + /// newline characters and leading whitespace. + pub line_spans: Vec, } impl<'a> Iterator for Parser<'a> { @@ -235,10 +240,15 @@ impl<'a> Iterator for Parser<'a> { None } } - '\n' => Some(String(self.string(pos))), _ => Some(String(self.string(pos))), } } else { + if self.is_literal && self.cur_line_start != self.input.len() { + let start = self.to_span_index(self.cur_line_start); + let end = self.to_span_index(self.input.len()); + self.line_spans.push(start.to(end)); + self.cur_line_start = self.input.len(); + } None } } @@ -266,6 +276,8 @@ impl<'a> Parser<'a> { last_opening_brace: None, append_newline, is_literal, + cur_line_start: 0, + line_spans: vec![], } } @@ -433,7 +445,17 @@ impl<'a> Parser<'a> { '{' | '}' => { return &self.input[start..pos]; } + '\n' if self.is_literal => { + let start = self.to_span_index(self.cur_line_start); + let end = self.to_span_index(pos); + self.line_spans.push(start.to(end)); + self.cur_line_start = pos + 1; + self.cur.next(); + } _ => { + if self.is_literal && pos == self.cur_line_start && c.is_whitespace() { + self.cur_line_start = pos + c.len_utf8(); + } self.cur.next(); } } diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 30bb5c0bffa6a..efcf95ec706b8 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -1252,7 +1252,7 @@ pub enum ExprKind { Ret(Option>), /// Output of the `asm!()` macro. - InlineAsm(InlineAsm), + InlineAsm(P), /// Output of the `llvm_asm!()` macro. LlvmInlineAsm(P), @@ -1971,6 +1971,7 @@ pub struct InlineAsm { pub template: Vec, pub operands: Vec<(InlineAsmOperand, Span)>, pub options: InlineAsmOptions, + pub line_spans: Vec, } /// Inline assembly dialect. diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 5bcd111706f35..fd69f5c1e5f89 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -1265,7 +1265,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let operands = self.arena.alloc_from_iter(operands); let template = self.arena.alloc_from_iter(asm.template.iter().cloned()); - let hir_asm = hir::InlineAsm { template, operands, options: asm.options }; + let line_spans = self.arena.alloc_slice(&asm.line_spans[..]); + let hir_asm = hir::InlineAsm { template, operands, options: asm.options, line_spans }; hir::ExprKind::InlineAsm(self.arena.alloc(hir_asm)) } diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 224b52b239f43..19fae63557289 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -513,10 +513,16 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P for Builder<'a, 'll, 'tcx> { ia.volatile, ia.alignstack, ia.dialect, - span, + &[span], ); if r.is_none() { return false; @@ -119,7 +119,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { template: &[InlineAsmTemplatePiece], operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, - span: Span, + line_spans: &[Span], ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); @@ -286,9 +286,9 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { volatile, alignstack, dialect, - span, + line_spans, ) - .unwrap_or_else(|| span_bug!(span, "LLVM asm constraint validation failed")); + .unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed")); if options.contains(InlineAsmOptions::PURE) { if options.contains(InlineAsmOptions::NOMEM) { @@ -340,7 +340,7 @@ fn inline_asm_call( volatile: bool, alignstack: bool, dia: LlvmAsmDialect, - span: Span, + line_spans: &[Span], ) -> Option<&'ll Value> { let volatile = if volatile { llvm::True } else { llvm::False }; let alignstack = if alignstack { llvm::True } else { llvm::False }; @@ -381,8 +381,24 @@ fn inline_asm_call( key.len() as c_uint, ); - let val: &'ll Value = bx.const_i32(span.ctxt().outer_expn().as_u32() as i32); - llvm::LLVMSetMetadata(call, kind, llvm::LLVMMDNodeInContext(bx.llcx, &val, 1)); + // srcloc contains one integer for each line of assembly code. + // Unfortunately this isn't enough to encode a full span so instead + // we just encode the start position of each line. + // FIXME: Figure out a way to pass the entire line spans. + let mut srcloc = vec![]; + if dia == LlvmAsmDialect::Intel && line_spans.len() > 1 { + // LLVM inserts an extra line to add the ".intel_syntax", so add + // a dummy srcloc entry for it. + // + // Don't do this if we only have 1 line span since that may be + // due to the asm template string coming from a macro. LLVM will + // default to the first srcloc for lines that don't have an + // associated srcloc. + srcloc.push(bx.const_i32(0)); + } + srcloc.extend(line_spans.iter().map(|span| bx.const_i32(span.lo().to_u32() as i32))); + let md = llvm::LLVMMDNodeInContext(bx.llcx, srcloc.as_ptr(), srcloc.len() as u32); + llvm::LLVMSetMetadata(call, kind, md); Some(call) } else { diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 57e018bba6a1a..02a9294930d2b 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -23,6 +23,7 @@ use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath}; use rustc_session::Session; +use rustc_span::InnerSpan; use rustc_target::spec::{CodeModel, RelocModel}; use libc::{c_char, c_int, c_uint, c_void, size_t}; @@ -238,12 +239,19 @@ impl<'a> Drop for DiagnosticHandlers<'a> { } } -unsafe extern "C" fn report_inline_asm( +fn report_inline_asm( cgcx: &CodegenContext, - msg: &str, - cookie: c_uint, + msg: String, + mut cookie: c_uint, + source: Option<(String, Vec)>, ) { - cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_owned()); + // In LTO build we may get srcloc values from other crates which are invalid + // since they use a different source map. To be safe we just suppress these + // in LTO builds. + if matches!(cgcx.lto, Lto::Fat | Lto::Thin) { + cookie = 0; + } + cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, source); } unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void, cookie: c_uint) { @@ -252,10 +260,37 @@ unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void } let (cgcx, _) = *(user as *const (&CodegenContext, &Handler)); - let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) - .expect("non-UTF8 SMDiagnostic"); + // Recover the post-substitution assembly code from LLVM for better + // diagnostics. + let mut have_source = false; + let mut buffer = String::new(); + let mut loc = 0; + let mut ranges = [0; 8]; + let mut num_ranges = ranges.len() / 2; + let msg = llvm::build_string(|msg| { + buffer = llvm::build_string(|buffer| { + have_source = llvm::LLVMRustUnpackSMDiagnostic( + diag, + msg, + buffer, + &mut loc, + ranges.as_mut_ptr(), + &mut num_ranges, + ); + }) + .expect("non-UTF8 inline asm"); + }) + .expect("non-UTF8 SMDiagnostic"); + + let source = have_source.then(|| { + let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)]; + for i in 0..num_ranges { + spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize)); + } + (buffer, spans) + }); - report_inline_asm(cgcx, &msg, cookie); + report_inline_asm(cgcx, msg, cookie, source); } unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { @@ -266,7 +301,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::InlineAsm(inline) => { - report_inline_asm(cgcx, &llvm::twine_to_string(inline.message), inline.cookie); + report_inline_asm(cgcx, llvm::twine_to_string(inline.message), inline.cookie, None); } llvm::diagnostic::Optimization(opt) => { diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 3fb7ff3cb8dfd..759c2bf1b85f4 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -2070,7 +2070,14 @@ extern "C" { ); #[allow(improper_ctypes)] - pub fn LLVMRustWriteSMDiagnosticToString(d: &SMDiagnostic, s: &RustString); + pub fn LLVMRustUnpackSMDiagnostic( + d: &SMDiagnostic, + message_out: &RustString, + buffer_out: &RustString, + loc_out: &mut c_uint, + ranges_out: *mut c_uint, + num_ranges: &mut usize, + ) -> bool; pub fn LLVMRustWriteArchive( Dst: *const c_char, diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 9e03c283cfb5c..cb5c95c11fad8 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -31,9 +31,9 @@ use rustc_session::cgu_reuse_tracker::CguReuseTracker; use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType}; use rustc_session::config::{Passes, Sanitizer, SwitchWithOptPath}; use rustc_session::Session; -use rustc_span::hygiene::ExpnId; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span}; use rustc_target::spec::{MergeFunctions, PanicStrategy}; use std::any::Any; @@ -1551,7 +1551,7 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem enum SharedEmitterMessage { Diagnostic(Diagnostic), - InlineAsmError(u32, String), + InlineAsmError(u32, String, Option<(String, Vec)>), AbortIfErrors, Fatal(String), } @@ -1572,8 +1572,13 @@ impl SharedEmitter { (SharedEmitter { sender }, SharedEmitterMain { receiver }) } - pub fn inline_asm_error(&self, cookie: u32, msg: String) { - drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg))); + pub fn inline_asm_error( + &self, + cookie: u32, + msg: String, + source: Option<(String, Vec)>, + ) { + drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, source))); } pub fn fatal(&self, msg: &str) { @@ -1626,8 +1631,30 @@ impl SharedEmitterMain { } handler.emit_diagnostic(&d); } - Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => { - sess.span_err(ExpnId::from_u32(cookie).expn_data().call_site, &msg) + Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, source)) => { + let msg = msg.strip_prefix("error: ").unwrap_or(&msg); + + // If the cookie is 0 then we don't have span information. + let mut err = if cookie == 0 { + sess.struct_err(&msg) + } else { + let pos = BytePos::from_u32(cookie); + let span = Span::with_root_ctxt(pos, pos); + sess.struct_span_err(span, &msg) + }; + + // Point to the generated assembly if it is available. + if let Some((buffer, spans)) = source { + let source = sess + .source_map() + .new_source_file(FileName::inline_asm_source_code(&buffer), buffer); + let source_span = Span::with_root_ctxt(source.start_pos, source.end_pos); + let spans: Vec<_> = + spans.iter().map(|sp| source_span.from_inner(*sp)).collect(); + err.span_note(spans, "instantiated into assembly here"); + } + + err.emit(); } Ok(SharedEmitterMessage::AbortIfErrors) => { sess.abort_if_errors(); diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index b487ed8dea8b6..e0c6fb451fc41 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -831,6 +831,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { template: &[ast::InlineAsmTemplatePiece], operands: &[mir::InlineAsmOperand<'tcx>], options: ast::InlineAsmOptions, + line_spans: &[Span], destination: Option, ) { let span = terminator.source_info.span; @@ -931,7 +932,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); - bx.codegen_inline_asm(template, &operands, options, span); + bx.codegen_inline_asm(template, &operands, options, line_spans); if let Some(target) = destination { helper.funclet_br(self, &mut bx, target); @@ -1034,7 +1035,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("borrowck false edges in codegen") } - mir::TerminatorKind::InlineAsm { template, ref operands, options, destination } => { + mir::TerminatorKind::InlineAsm { + template, + ref operands, + options, + line_spans, + destination, + } => { self.codegen_asm_terminator( helper, bx, @@ -1042,6 +1049,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { template, operands, options, + line_spans, destination, ); } diff --git a/src/librustc_codegen_ssa/traits/asm.rs b/src/librustc_codegen_ssa/traits/asm.rs index 0abfdfde7801b..b6b57744f95b6 100644 --- a/src/librustc_codegen_ssa/traits/asm.rs +++ b/src/librustc_codegen_ssa/traits/asm.rs @@ -52,7 +52,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes { template: &[InlineAsmTemplatePiece], operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, - span: Span, + line_spans: &[Span], ); } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 35cff668581dd..0194dc9f90bb8 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2106,6 +2106,7 @@ pub struct InlineAsm<'hir> { pub template: &'hir [InlineAsmTemplatePiece], pub operands: &'hir [InlineAsmOperand<'hir>], pub options: InlineAsmOptions, + pub line_spans: &'hir [Span], } #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic, PartialEq)] diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 47cfa62abb14d..f6a236d38ecc3 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -1193,6 +1193,10 @@ pub enum TerminatorKind<'tcx> { /// Miscellaneous options for the inline assembly. options: InlineAsmOptions, + /// Source spans for each line of the inline assembly code. These are + /// used to map assembler errors back to the line in the source code. + line_spans: &'tcx [Span], + /// Destination block after the inline assembly returns, unless it is /// diverging (InlineAsmOptions::NORETURN). destination: Option, @@ -1595,7 +1599,7 @@ impl<'tcx> TerminatorKind<'tcx> { } FalseEdges { .. } => write!(fmt, "falseEdges"), FalseUnwind { .. } => write!(fmt, "falseUnwind"), - InlineAsm { template, ref operands, options, destination: _ } => { + InlineAsm { template, ref operands, options, .. } => { write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?; for op in operands { write!(fmt, ", ")?; diff --git a/src/librustc_middle/mir/type_foldable.rs b/src/librustc_middle/mir/type_foldable.rs index bb7001c1207bf..b0207b469fa64 100644 --- a/src/librustc_middle/mir/type_foldable.rs +++ b/src/librustc_middle/mir/type_foldable.rs @@ -78,9 +78,13 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { FalseEdges { real_target, imaginary_target } } FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, - InlineAsm { template, ref operands, options, destination } => { - InlineAsm { template, operands: operands.fold_with(folder), options, destination } - } + InlineAsm { template, ref operands, options, line_spans, destination } => InlineAsm { + template, + operands: operands.fold_with(folder), + options, + line_spans, + destination, + }, }; Terminator { source_info: self.source_info, kind } } diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs index a29b7b75294b7..035e6e55a975d 100644 --- a/src/librustc_middle/mir/visit.rs +++ b/src/librustc_middle/mir/visit.rs @@ -535,6 +535,7 @@ macro_rules! make_mir_visitor { template: _, operands, options: _, + line_spans: _, destination: _, } => { for op in operands { diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs index 178e3db17cd32..0b59e29b66c74 100644 --- a/src/librustc_mir/borrow_check/invalidation.rs +++ b/src/librustc_mir/borrow_check/invalidation.rs @@ -183,7 +183,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } } } - TerminatorKind::InlineAsm { template: _, ref operands, options: _, destination: _ } => { + TerminatorKind::InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination: _, + } => { for op in operands { match *op { InlineAsmOperand::In { reg: _, ref value } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index a0c1d96bb4743..525c054a7665a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -724,7 +724,13 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state); } - TerminatorKind::InlineAsm { template: _, ref operands, options: _, destination: _ } => { + TerminatorKind::InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination: _, + } => { for op in operands { match *op { InlineAsmOperand::In { reg: _, ref value } diff --git a/src/librustc_mir/dataflow/framework/direction.rs b/src/librustc_mir/dataflow/framework/direction.rs index 97b14ea771b2f..9e2a28853e151 100644 --- a/src/librustc_mir/dataflow/framework/direction.rs +++ b/src/librustc_mir/dataflow/framework/direction.rs @@ -482,7 +482,7 @@ impl Direction for Forward { } } - InlineAsm { template: _, operands: _, options: _, destination } => { + InlineAsm { template: _, operands: _, options: _, line_spans: _, destination } => { if let Some(target) = destination { propagate(target, exit_state); } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 427ab1ca5cd22..e35d853c92815 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -411,7 +411,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.gather_init(destination.as_ref(), InitKind::NonPanicPathOnly); } } - TerminatorKind::InlineAsm { template: _, ref operands, options: _, destination: _ } => { + TerminatorKind::InlineAsm { + template: _, + ref operands, + options: _, + line_spans: _, + destination: _ + } => { for op in operands { match *op { InlineAsmOperand::In { reg: _, ref value } diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs index ff3c7ee3ee823..e7733deee4dd3 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/src/librustc_mir_build/build/expr/into.rs @@ -310,7 +310,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); block.unit() } - ExprKind::InlineAsm { template, operands, options } => { + ExprKind::InlineAsm { template, operands, options, line_spans } => { use crate::hair; use rustc_middle::mir; let operands = operands @@ -368,6 +368,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { template, operands, options, + line_spans, destination: if options.contains(InlineAsmOptions::NORETURN) { None } else { diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index 114bf5710402f..056cb9d98ce3b 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -513,6 +513,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( }) .collect(), options: asm.options, + line_spans: asm.line_spans, }, hir::ExprKind::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm { diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs index aba7a7a1b420c..0a1c68e83a94c 100644 --- a/src/librustc_mir_build/hair/mod.rs +++ b/src/librustc_mir_build/hair/mod.rs @@ -283,6 +283,7 @@ crate enum ExprKind<'tcx> { template: &'tcx [InlineAsmTemplatePiece], operands: Vec>, options: InlineAsmOptions, + line_spans: &'tcx [Span], }, LlvmInlineAsm { asm: &'tcx hir::LlvmInlineAsmInner, diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 58cdb87158afe..616876d4b02a8 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -101,6 +101,8 @@ pub enum FileName { /// Custom sources for explicit parser calls from plugins and drivers. Custom(String), DocTest(PathBuf, isize), + /// Post-substitution inline assembly from LLVM + InlineAsm(u64), } impl std::fmt::Display for FileName { @@ -116,6 +118,7 @@ impl std::fmt::Display for FileName { CliCrateAttr(_) => write!(fmt, ""), Custom(ref s) => write!(fmt, "<{}>", s), DocTest(ref path, _) => write!(fmt, "{}", path.display()), + InlineAsm(_) => write!(fmt, ""), } } } @@ -139,7 +142,8 @@ impl FileName { | CliCrateAttr(_) | Custom(_) | QuoteExpansion(_) - | DocTest(_, _) => false, + | DocTest(_, _) + | InlineAsm(_) => false, } } @@ -182,6 +186,12 @@ impl FileName { pub fn doc_test_source_code(path: PathBuf, line: isize) -> FileName { FileName::DocTest(path, line) } + + pub fn inline_asm_source_code(src: &str) -> FileName { + let mut hasher = StableHasher::new(); + src.hash(&mut hasher); + FileName::InlineAsm(hasher.finish()) + } } /// Spans represent a region of code, used for error reporting. Positions in spans diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 24f35627d10e5..6fac2662506a1 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1216,10 +1216,33 @@ extern "C" void LLVMRustSetInlineAsmDiagnosticHandler( unwrap(C)->setInlineAsmDiagnosticHandler(H, CX); } -extern "C" void LLVMRustWriteSMDiagnosticToString(LLVMSMDiagnosticRef D, - RustStringRef Str) { - RawRustStringOstream OS(Str); - unwrap(D)->print("", OS); +extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, + RustStringRef MessageOut, + RustStringRef BufferOut, + unsigned* LocOut, + unsigned* RangesOut, + size_t* NumRanges) { + SMDiagnostic& D = *unwrap(DRef); + RawRustStringOstream MessageOS(MessageOut); + MessageOS << D.getMessage(); + + if (D.getLoc() == SMLoc()) + return false; + + const SourceMgr &LSM = *D.getSourceMgr(); + const MemoryBuffer *LBuf = LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); + LLVMRustStringWriteImpl(BufferOut, LBuf->getBufferStart(), LBuf->getBufferSize()); + + *LocOut = D.getLoc().getPointer() - LBuf->getBufferStart(); + + *NumRanges = std::min(*NumRanges, D.getRanges().size()); + size_t LineStart = *LocOut - (size_t)D.getColumnNo(); + for (size_t i = 0; i < *NumRanges; i++) { + RangesOut[i * 2] = LineStart + D.getRanges()[i].first; + RangesOut[i * 2 + 1] = LineStart + D.getRanges()[i].second; + } + + return true; } extern "C" LLVMValueRef LLVMRustBuildCleanupPad(LLVMBuilderRef B, diff --git a/src/test/ui/asm/srcloc.rs b/src/test/ui/asm/srcloc.rs new file mode 100644 index 0000000000000..7af6f620a9858 --- /dev/null +++ b/src/test/ui/asm/srcloc.rs @@ -0,0 +1,41 @@ +// no-system-llvm +// only-x86_64 +// build-fail + +#![feature(asm)] + +// Checks that inline asm errors are mapped to the correct line in the source code. + +fn main() { + unsafe { + asm!("invalid_instruction"); + //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(" + invalid_instruction + "); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(r#" + invalid_instruction + "#); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(" + mov eax, eax + invalid_instruction + mov eax, eax + "); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(r#" + mov eax, eax + invalid_instruction + mov eax, eax + "#); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!(concat!("invalid", "_", "instruction")); + //~^ ERROR: invalid instruction mnemonic 'invalid_instruction' + } +} diff --git a/src/test/ui/asm/srcloc.stderr b/src/test/ui/asm/srcloc.stderr new file mode 100644 index 0000000000000..57a4fbb974228 --- /dev/null +++ b/src/test/ui/asm/srcloc.stderr @@ -0,0 +1,74 @@ +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:11:15 + | +LL | asm!("invalid_instruction"); + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:15:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:20:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:26:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:33:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:38:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/issues/issue-23458.stderr b/src/test/ui/issues/issue-23458.stderr index 81f06e6397542..a6500b9bb4c24 100644 --- a/src/test/ui/issues/issue-23458.stderr +++ b/src/test/ui/issues/issue-23458.stderr @@ -2,16 +2,19 @@ error: invalid operand in inline asm: 'int $3' --> $DIR/issue-23458.rs:8:9 | LL | llvm_asm!("int $3"); - | ^^^^^^^^^^^^^^^^^^^^ - -error: :1:2: error: too few operands for instruction - int - ^ + | ^ +error: too few operands for instruction --> $DIR/issue-23458.rs:8:9 | LL | llvm_asm!("int $3"); - | ^^^^^^^^^^^^^^^^^^^^ + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | int + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/llvm-asm/issue-69092.rs b/src/test/ui/llvm-asm/issue-69092.rs index ecce7bfdf5bba..96c019b760e95 100644 --- a/src/test/ui/llvm-asm/issue-69092.rs +++ b/src/test/ui/llvm-asm/issue-69092.rs @@ -6,5 +6,5 @@ fn main() { unsafe { llvm_asm!(".ascii \"Xen\0\""); } - //~^ ERROR: :1:9: error: expected string in '.ascii' directive + //~^ ERROR: expected string in '.ascii' directive } diff --git a/src/test/ui/llvm-asm/issue-69092.stderr b/src/test/ui/llvm-asm/issue-69092.stderr index 35f77edc3c402..2ca86cf7c1b99 100644 --- a/src/test/ui/llvm-asm/issue-69092.stderr +++ b/src/test/ui/llvm-asm/issue-69092.stderr @@ -1,11 +1,14 @@ -error: :1:9: error: expected string in '.ascii' directive - .ascii "Xen - ^ - +error: expected string in '.ascii' directive --> $DIR/issue-69092.rs:8:14 | LL | unsafe { llvm_asm!(".ascii \"Xen\0\""); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ + | +note: instantiated into assembly here + --> :1:9 + | +LL | .ascii "Xen + | ^ error: aborting due to previous error From fc497f79b3a60e23da08680d66e6cfc00a716bcc Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 26 May 2020 22:44:43 +0100 Subject: [PATCH 428/695] Add Span to arena_types! for decoding &'tcx [Span] --- src/librustc_middle/arena.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index 9b9207312e8dd..d5212ec5c3081 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -82,6 +82,8 @@ macro_rules! arena_types { // (during lowering) and the `librustc_middle` arena (for decoding MIR) [decode] asm_template: rustc_ast::ast::InlineAsmTemplatePiece, + // This is used to decode the &'tcx [Span] for InlineAsm's line_spans. + [decode] span: rustc_span::Span, ], $tcx); ) } From 692f4ec3b103a36830132bc941c2aa2abea4b7e7 Mon Sep 17 00:00:00 2001 From: XAMPPRocky <4464295+XAMPPRocky@users.noreply.github.com> Date: Fri, 29 May 2020 18:25:34 +0200 Subject: [PATCH 429/695] Update RELEASES.md --- RELEASES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 7ee61c34b7085..7cba27e134a78 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -103,6 +103,11 @@ Compatibility Notes - [`mem::{zeroed, uninitialised, MaybeUninit}` will now panic when used with types that do not allow zero initialization such as `NonZeroU8`.][66059] This was previously a warning. +- [In 1.45.0 (the next release) converting a `f64` to `u32` using the `as` + operator has been defined as a saturating operation.][71269] This was previously + undefined behaviour, you can use the `{f64, f32}::to_int_unchecked` methods to + continue using the current behaviour which may desirable in rare performance + sensitive situations. Internal Only ------------- @@ -127,6 +132,7 @@ related tools. [70048]: https://github.com/rust-lang/rust/pull/70048/ [70081]: https://github.com/rust-lang/rust/pull/70081/ [70156]: https://github.com/rust-lang/rust/pull/70156/ +[71269]: https://github.com/rust-lang/rust/pull/71269/ [69838]: https://github.com/rust-lang/rust/pull/69838/ [69929]: https://github.com/rust-lang/rust/pull/69929/ [69661]: https://github.com/rust-lang/rust/pull/69661/ From 222fbd20f2b907ac19303906bda44f6d63fe84a4 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 29 May 2020 18:47:40 +0200 Subject: [PATCH 430/695] fix encode with shorthand for Predicate --- src/librustc_middle/ty/codec.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_middle/ty/codec.rs b/src/librustc_middle/ty/codec.rs index c4d5bd7e60255..8bc69a9d12312 100644 --- a/src/librustc_middle/ty/codec.rs +++ b/src/librustc_middle/ty/codec.rs @@ -39,9 +39,9 @@ impl<'tcx> EncodableWithShorthand for Ty<'tcx> { } impl<'tcx> EncodableWithShorthand for ty::Predicate<'tcx> { - type Variant = ty::Predicate<'tcx>; + type Variant = ty::PredicateKind<'tcx>; fn variant(&self) -> &Self::Variant { - self + self.kind() } } From 0d18136b776cd7cda2c4932f447e6484377f42b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 29 May 2020 09:44:41 -0700 Subject: [PATCH 431/695] Move common code to `WhereClause` --- src/librustc_hir/hir.rs | 7 +++++++ src/librustc_middle/ty/diagnostics.rs | 13 +------------ .../traits/error_reporting/suggestions.rs | 11 +---------- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index ef398ab25d3fb..a46871ac80798 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -525,6 +525,13 @@ impl WhereClause<'_> { pub fn span_for_predicates_or_empty_place(&self) -> Span { self.span } + + /// `Span` where further predicates would be suggested, accounting for trailing commas, like + /// in `fn foo(t: T) where T: Foo,` so we don't suggest two trailing commas. + pub fn tail_span_for_suggestion(&self) -> Span { + let end = self.span_for_predicates_or_empty_place().shrink_to_hi(); + self.predicates.last().map(|p| p.span()).unwrap_or(end).shrink_to_hi().to(end) + } } /// A single predicate in a where-clause. diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index 96c36d989e928..ba3cc0a7af2c6 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -220,22 +220,11 @@ pub fn suggest_constraining_type_param( } } - // Account for `fn foo(t: T) where T: Foo,` so we don't suggest two trailing commas. - let end = generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(); - let where_clause_span = generics - .where_clause - .predicates - .last() - .map(|p| p.span()) - .unwrap_or(end) - .shrink_to_hi() - .to(end); - match ¶m_spans[..] { &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), _ => { err.span_suggestion_verbose( - where_clause_span, + generics.where_clause.tail_span_for_suggestion(), &msg_restrict_type_further, format!(", {}: {}", param_name, constraint), Applicability::MachineApplicable, diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index eb281b270ff2a..a8d4de873f958 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -169,17 +169,8 @@ pub trait InferCtxtExt<'tcx> { } fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { - let end = generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(); ( - // Account for `where T: Foo,` so we don't suggest two trailing commas. - generics - .where_clause - .predicates - .last() - .map(|p| p.span()) - .unwrap_or(end) - .shrink_to_hi() - .to(end), + generics.where_clause.tail_span_for_suggestion(), format!( "{} {}", if !generics.where_clause.predicates.is_empty() { "," } else { " where" }, From 15955772276e5574414a6ff630495a9898a99efb Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 29 May 2020 19:48:47 +0200 Subject: [PATCH 432/695] Borrow<[T]> for Interned<'tcx, List> --- src/librustc_middle/ty/context.rs | 50 ++----------------------------- 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 7a20014484190..a2e8771e05895 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1924,32 +1924,8 @@ impl<'tcx, T: Hash> Hash for Interned<'tcx, List> { } } -impl<'tcx> Borrow<[Ty<'tcx>]> for Interned<'tcx, List>> { - fn borrow<'a>(&'a self) -> &'a [Ty<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[CanonicalVarInfo]> for Interned<'tcx, List> { - fn borrow(&self) -> &[CanonicalVarInfo] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[GenericArg<'tcx>]> for Interned<'tcx, InternalSubsts<'tcx>> { - fn borrow<'a>(&'a self) -> &'a [GenericArg<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[ProjectionKind]> for Interned<'tcx, List> { - fn borrow(&self) -> &[ProjectionKind] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[PlaceElem<'tcx>]> for Interned<'tcx, List>> { - fn borrow(&self) -> &[PlaceElem<'tcx>] { +impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List> { + fn borrow<'a>(&'a self) -> &'a [T] { &self.0[..] } } @@ -1960,34 +1936,12 @@ impl<'tcx> Borrow for Interned<'tcx, RegionKind> { } } -impl<'tcx> Borrow<[ExistentialPredicate<'tcx>]> - for Interned<'tcx, List>> -{ - fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[Predicate<'tcx>]> for Interned<'tcx, List>> { - fn borrow<'a>(&'a self) -> &'a [Predicate<'tcx>] { - &self.0[..] - } -} - impl<'tcx> Borrow> for Interned<'tcx, Const<'tcx>> { fn borrow<'a>(&'a self) -> &'a Const<'tcx> { &self.0 } } -impl<'tcx> Borrow<[traits::ChalkEnvironmentClause<'tcx>]> - for Interned<'tcx, List>> -{ - fn borrow<'a>(&'a self) -> &'a [traits::ChalkEnvironmentClause<'tcx>] { - &self.0[..] - } -} - impl<'tcx> Borrow> for Interned<'tcx, PredicateKind<'tcx>> { fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> { &self.0 From 21abc8879cddd0002ca1da2eaa0f8e27ef09fa99 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Fri, 29 May 2020 11:14:27 -0700 Subject: [PATCH 433/695] Make libunwind build hermetic We want to avoid exporting any symbols from Rust's version of libunwind, and to do so we need to disable visibility annotations to make sure that the -fvisibility=hidden has effect, and also hide global new/delete. This matches the CMake build of libunwind. --- src/libunwind/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index 1462639259cb8..00749d93d55b0 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -90,6 +90,8 @@ mod llvm_libunwind { cfg.flag("-fstrict-aliasing"); cfg.flag("-funwind-tables"); cfg.flag("-fvisibility=hidden"); + cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); + cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); } let mut unwind_sources = vec![ From 25bafc24db9559db2fb3688d824a2a41ada150e5 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 29 May 2020 20:41:26 +0200 Subject: [PATCH 434/695] remove mk_bool --- src/librustc_middle/ty/context.rs | 5 ----- src/librustc_typeck/check/op.rs | 8 ++++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 7a20014484190..49d751ea8aecc 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -2251,11 +2251,6 @@ impl<'tcx> TyCtxt<'tcx> { if self.features().never_type_fallback { self.types.never } else { self.types.unit } } - #[inline] - pub fn mk_bool(self) -> Ty<'tcx> { - self.mk_ty(Bool) - } - #[inline] pub fn mk_fn_def(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> { self.mk_ty(FnDef(def_id, substs)) diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 00ff2af82e303..d89993e354768 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -121,9 +121,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { - self.demand_suptype(*lhs_span, tcx.mk_bool(), lhs_ty); - self.demand_suptype(*rhs_span, tcx.mk_bool(), rhs_ty); - tcx.mk_bool() + self.demand_suptype(*lhs_span, tcx.types.bool, lhs_ty); + self.demand_suptype(*rhs_span, tcx.types.bool, rhs_ty); + tcx.types.bool } BinOpCategory::Shift => { @@ -140,7 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { BinOpCategory::Comparison => { // both LHS and RHS and result will have the same type self.demand_suptype(*rhs_span, lhs_ty, rhs_ty); - tcx.mk_bool() + tcx.types.bool } } } From 8f8cb710cc682cdb29d21cfa39af88c7e8534d76 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 29 May 2020 21:04:01 +0200 Subject: [PATCH 435/695] remove trivial `mk_predicate`s --- src/librustc_middle/ty/structural_impls.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index c6ecb08615fcf..7eefd1419a311 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -987,7 +987,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - folder.tcx().mk_predicate(ty::PredicateKind::super_fold_with(self.kind, folder)) + let new = ty::PredicateKind::super_fold_with(self.kind, folder); + if new != *self.kind { folder.tcx().mk_predicate(new) } else { *self } } fn super_visit_with>(&self, visitor: &mut V) -> bool { From 2f3dd7b187027e601b9711aefc2b1383c5cf5961 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sun, 24 May 2020 23:39:39 +0100 Subject: [PATCH 436/695] Remove remaining calls to `as_local_node_id` --- src/librustc_ast_lowering/item.rs | 11 +++--- src/librustc_hir/definitions.rs | 11 ------ src/librustc_resolve/build_reduced_graph.rs | 20 +++++++---- src/librustc_resolve/late.rs | 3 +- src/librustc_resolve/lib.rs | 40 +++++++++++++-------- src/librustc_resolve/macros.rs | 8 ++--- 6 files changed, 50 insertions(+), 43 deletions(-) diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index eced17c9245f2..47d10f86d03e2 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -1321,12 +1321,15 @@ impl<'hir> LoweringContext<'_, 'hir> { .get_partial_res(bound_pred.bounded_ty.id) .map(|d| d.base_res()) { - if let Some(node_id) = - self.resolver.definitions().as_local_node_id(def_id) - { + if let Some(def_id) = def_id.as_local() { for param in &generics.params { if let GenericParamKind::Type { .. } = param.kind { - if node_id == param.id { + if def_id + == self + .resolver + .definitions() + .local_def_id(param.id) + { add_bounds .entry(param.id) .or_default() diff --git a/src/librustc_hir/definitions.rs b/src/librustc_hir/definitions.rs index c7a0822d27dd6..c8971c2f9adbd 100644 --- a/src/librustc_hir/definitions.rs +++ b/src/librustc_hir/definitions.rs @@ -332,17 +332,6 @@ impl Definitions { }) } - #[inline] - pub fn as_local_node_id(&self, def_id: DefId) -> Option { - if let Some(def_id) = def_id.as_local() { - let node_id = self.def_id_to_node_id[def_id]; - if node_id != ast::DUMMY_NODE_ID { - return Some(node_id); - } - } - None - } - #[inline] pub fn as_local_hir_id(&self, def_id: LocalDefId) -> hir::HirId { self.local_def_id_to_hir_id(def_id) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 92ea119d9a458..9ee3d989bf3f1 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -25,7 +25,7 @@ use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::SyntaxExtension; use rustc_expand::expand::AstFragment; use rustc_hir::def::{self, *}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_metadata::creader::LoadedMacro; use rustc_middle::bug; use rustc_middle::hir::exports::Export; @@ -1150,15 +1150,22 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // Mark the given macro as unused unless its name starts with `_`. // Macro uses will remove items from this set, and the remaining // items will be reported as `unused_macros`. - fn insert_unused_macro(&mut self, ident: Ident, node_id: NodeId, span: Span) { + fn insert_unused_macro( + &mut self, + ident: Ident, + def_id: LocalDefId, + node_id: NodeId, + span: Span, + ) { if !ident.as_str().starts_with('_') { - self.r.unused_macros.insert(node_id, span); + self.r.unused_macros.insert(def_id, (node_id, span)); } } fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> { let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; + let def_id = self.r.definitions.local_def_id(item.id); let (ext, ident, span, macro_rules) = match &item.kind { ItemKind::MacroDef(def) => { let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition())); @@ -1166,7 +1173,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } ItemKind::Fn(..) => match Self::proc_macro_stub(item) { Some((macro_kind, ident, span)) => { - self.r.proc_macro_stubs.insert(item.id); + self.r.proc_macro_stubs.insert(def_id); (self.r.dummy_ext(macro_kind), ident, span, false) } None => return parent_scope.macro_rules, @@ -1174,7 +1181,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { _ => unreachable!(), }; - let def_id = self.r.definitions.local_def_id(item.id); let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id.to_def_id()); self.r.macro_map.insert(def_id.to_def_id(), ext); self.r.local_macro_def_scopes.insert(def_id, parent_scope.module); @@ -1196,7 +1202,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport)); } else { self.r.check_reserved_macro_name(ident, res); - self.insert_unused_macro(ident, item.id, span); + self.insert_unused_macro(ident, def_id, item.id, span); } MacroRulesScope::Binding(self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding { parent_macro_rules_scope: parent_scope.macro_rules, @@ -1214,7 +1220,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { _ => self.resolve_visibility(&item.vis), }; if vis != ty::Visibility::Public { - self.insert_unused_macro(ident, item.id, span); + self.insert_unused_macro(ident, def_id, item.id, span); } self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); self.parent_scope.macro_rules diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index f04813cf3bc7f..3b49b3b6ff7d2 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1621,11 +1621,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let report_errors = |this: &mut Self, res: Option| { let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); let def_id = this.parent_scope.module.normal_ancestor_id; - let node_id = this.r.definitions.as_local_node_id(def_id).unwrap(); let better = res.is_some(); let suggestion = if res.is_none() { this.report_missing_type_error(path) } else { None }; - this.r.use_injections.push(UseError { err, candidates, node_id, better, suggestion }); + this.r.use_injections.push(UseError { err, candidates, def_id, better, suggestion }); PartialRes::new(Res::Err) }; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 015f1b6315c19..b50f9fe8e907d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -23,7 +23,7 @@ use rustc_ast::ast::{self, FloatTy, IntTy, NodeId, UintTy}; use rustc_ast::ast::{Crate, CRATE_NODE_ID}; use rustc_ast::ast::{ItemKind, Path}; use rustc_ast::attr; -use rustc_ast::node_id::{NodeMap, NodeSet}; +use rustc_ast::node_id::NodeMap; use rustc_ast::unwrap_or; use rustc_ast::visit::{self, Visitor}; use rustc_ast_pretty::pprust; @@ -253,21 +253,31 @@ impl<'a> From<&'a ast::PathSegment> for Segment { } } -struct UsePlacementFinder { - target_module: NodeId, +struct UsePlacementFinder<'d> { + definitions: &'d Definitions, + target_module: LocalDefId, span: Option, found_use: bool, } -impl UsePlacementFinder { - fn check(krate: &Crate, target_module: NodeId) -> (Option, bool) { - let mut finder = UsePlacementFinder { target_module, span: None, found_use: false }; - visit::walk_crate(&mut finder, krate); - (finder.span, finder.found_use) +impl<'d> UsePlacementFinder<'d> { + fn check( + definitions: &'d Definitions, + krate: &Crate, + target_module: DefId, + ) -> (Option, bool) { + if let Some(target_module) = target_module.as_local() { + let mut finder = + UsePlacementFinder { definitions, target_module, span: None, found_use: false }; + visit::walk_crate(&mut finder, krate); + (finder.span, finder.found_use) + } else { + (None, false) + } } } -impl<'tcx> Visitor<'tcx> for UsePlacementFinder { +impl<'tcx, 'd> Visitor<'tcx> for UsePlacementFinder<'d> { fn visit_mod( &mut self, module: &'tcx ast::Mod, @@ -278,7 +288,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder { if self.span.is_some() { return; } - if node_id != self.target_module { + if self.definitions.local_def_id(node_id) != self.target_module { visit::walk_mod(self, module); return; } @@ -611,7 +621,7 @@ struct UseError<'a> { /// Attach `use` statements for these candidates. candidates: Vec, /// The `NodeId` of the module to place the use-statements in. - node_id: NodeId, + def_id: DefId, /// Whether the diagnostic should state that it's "better". better: bool, /// Extra free form suggestion. Currently used to suggest new type parameter. @@ -926,8 +936,8 @@ pub struct Resolver<'a> { non_macro_attrs: [Lrc; 2], local_macro_def_scopes: FxHashMap>, ast_transform_scopes: FxHashMap>, - unused_macros: NodeMap, - proc_macro_stubs: NodeSet, + unused_macros: FxHashMap, + proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: Vec<(Ident, MacroKind, ParentScope<'a>, Option<&'a NameBinding<'a>>)>, @@ -2567,10 +2577,10 @@ impl<'a> Resolver<'a> { } fn report_with_use_injections(&mut self, krate: &Crate) { - for UseError { mut err, candidates, node_id, better, suggestion } in + for UseError { mut err, candidates, def_id, better, suggestion } in self.use_injections.drain(..) { - let (span, found_use) = UsePlacementFinder::check(krate, node_id); + let (span, found_use) = UsePlacementFinder::check(&self.definitions, krate, def_id); if !candidates.is_empty() { diagnostics::show_candidates(&mut err, span, &candidates, better, found_use); } else if let Some((span, msg, sugg, appl)) = suggestion { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7027c82626787..394d8dc4e1135 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -333,7 +333,7 @@ impl<'a> base::Resolver for Resolver<'a> { } fn check_unused_macros(&mut self) { - for (&node_id, &span) in self.unused_macros.iter() { + for (_, &(node_id, span)) in self.unused_macros.iter() { self.lint_buffer.buffer_lint(UNUSED_MACROS, node_id, span, "unused macro definition"); } } @@ -416,9 +416,9 @@ impl<'a> Resolver<'a> { match res { Res::Def(DefKind::Macro(_), def_id) => { - if let Some(node_id) = self.definitions.as_local_node_id(def_id) { - self.unused_macros.remove(&node_id); - if self.proc_macro_stubs.contains(&node_id) { + if let Some(def_id) = def_id.as_local() { + self.unused_macros.remove(&def_id); + if self.proc_macro_stubs.contains(&def_id) { self.session.span_err( path.span, "can't use a procedural macro from the same crate that defines it", From 21755b58c900cd5d14422ebd980fe11390e021fe Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 29 May 2020 21:51:46 +0300 Subject: [PATCH 437/695] rustc_lexer: Optimize shebang detection slightly --- src/librustc_lexer/src/lib.rs | 37 +++++++++---------- .../ui/parser/shebang/shebang-doc-comment.rs | 6 +++ .../parser/shebang/shebang-doc-comment.stderr | 8 ++++ 3 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/parser/shebang/shebang-doc-comment.rs create mode 100644 src/test/ui/parser/shebang/shebang-doc-comment.stderr diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index fe6785de009a1..c2139d07f378a 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -238,26 +238,25 @@ pub enum Base { /// `rustc` allows files to have a shebang, e.g. "#!/usr/bin/rustrun", /// but shebang isn't a part of rust syntax. pub fn strip_shebang(input: &str) -> Option { - let first_line = input.lines().next()?; - // A shebang is intentionally loosely defined as `#! [non whitespace]` on the first line. - let could_be_shebang = - first_line.starts_with("#!") && first_line[2..].contains(|c| !is_whitespace(c)); - if !could_be_shebang { - return None; - } - let non_whitespace_tokens = tokenize(input).map(|tok| tok.kind).filter(|tok| - !matches!(tok, TokenKind::LineComment | TokenKind::BlockComment { .. } | TokenKind::Whitespace) - ); - let prefix = [TokenKind::Pound, TokenKind::Not, TokenKind::OpenBracket]; - let starts_with_attribute = non_whitespace_tokens.take(3).eq(prefix.iter().copied()); - if starts_with_attribute { - // If the file starts with #![ then it's definitely not a shebang -- it couldn't be - // a rust program since a Rust program can't start with `[` - None - } else { - // It's a #!... and there isn't a `[` in sight, must be a shebang - Some(first_line.len()) + // Shebang must start with `#!` literally, without any preceding whitespace. + if input.starts_with("#!") { + let input_tail = &input[2..]; + // Shebang must have something non-whitespace after `#!` on the first line. + let first_line_tail = input_tail.lines().next()?; + if first_line_tail.contains(|c| !is_whitespace(c)) { + // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe + // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level), + // then it may be valid Rust code, so consider it Rust code. + let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).filter(|tok| + !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment | TokenKind::BlockComment { .. }) + ).next(); + if next_non_whitespace_token != Some(TokenKind::OpenBracket) { + // No other choice than to consider this a shebang. + return Some(2 + first_line_tail.len()); + } + } } + None } /// Parses the first token from the provided input string. diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.rs b/src/test/ui/parser/shebang/shebang-doc-comment.rs new file mode 100644 index 0000000000000..7dbb9eebc7571 --- /dev/null +++ b/src/test/ui/parser/shebang/shebang-doc-comment.rs @@ -0,0 +1,6 @@ +#!///bin/bash +[allow(unused_variables)] +//~^^ ERROR expected `[`, found doc comment + +// Doc comment is misinterpreted as a whitespace (regular comment) during shebang detection. +// Even if it wasn't, it would still result in an error, just a different one. diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.stderr b/src/test/ui/parser/shebang/shebang-doc-comment.stderr new file mode 100644 index 0000000000000..f524f556837fb --- /dev/null +++ b/src/test/ui/parser/shebang/shebang-doc-comment.stderr @@ -0,0 +1,8 @@ +error: expected `[`, found doc comment `///bin/bash` + --> $DIR/shebang-doc-comment.rs:1:3 + | +LL | #!///bin/bash + | ^^^^^^^^^^^ expected `[` + +error: aborting due to previous error + From 27ed143ba9bb96e907f56c9f294c904a2cb26123 Mon Sep 17 00:00:00 2001 From: Chris Simpkins Date: Fri, 29 May 2020 16:03:46 -0400 Subject: [PATCH 438/695] fix diagnostics for `@ ..` binding pattern in tuples and tuple structs fix comment add newline for tidy fmt error... edit suggestion message change the suggestion message to better handle cases with binding modes Apply suggestions from estebank code review Co-authored-by: Esteban Kuber edits to address source review Apply suggestions from estebank code review #2 Co-authored-by: Esteban Kuber update test files --- src/librustc_ast_lowering/pat.rs | 33 ++++++++++++++++++++++--- src/test/ui/issues/issue-72574-1.rs | 8 ++++++ src/test/ui/issues/issue-72574-1.stderr | 14 +++++++++++ src/test/ui/issues/issue-72574-2.rs | 10 ++++++++ src/test/ui/issues/issue-72574-2.stderr | 14 +++++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/issues/issue-72574-1.rs create mode 100644 src/test/ui/issues/issue-72574-1.stderr create mode 100644 src/test/ui/issues/issue-72574-2.rs create mode 100644 src/test/ui/issues/issue-72574-2.stderr diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs index 496e401d06124..55c1f80266337 100644 --- a/src/librustc_ast_lowering/pat.rs +++ b/src/librustc_ast_lowering/pat.rs @@ -3,6 +3,7 @@ use super::{ImplTraitContext, LoweringContext, ParamMode}; use rustc_ast::ast::*; use rustc_ast::ptr::P; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::symbol::Ident; @@ -102,10 +103,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Note that unlike for slice patterns, // where `xs @ ..` is a legal sub-slice pattern, // it is not a legal sub-tuple pattern. - if pat.is_rest() { - rest = Some((idx, pat.span)); - break; + match pat.kind { + // Found a sub-tuple rest pattern + PatKind::Rest => { + rest = Some((idx, pat.span)); + break; + } + // Found a sub-tuple pattern `$binding_mode $ident @ ..`. + // This is not allowed as a sub-tuple pattern + PatKind::Ident(ref _bm, ident, Some(ref sub)) if sub.is_rest() => { + rest = Some((idx, pat.span)); + let sp = pat.span; + self.diagnostic() + .struct_span_err( + sp, + &format!("`{} @` is not allowed in a {}", ident.name, ctx), + ) + .span_label(sp, "this is only allowed in slice patterns") + .help("remove this and bind each tuple field independently") + .span_suggestion_verbose( + sp, + &format!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident), + "..".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + break; + } + _ => {} } + // It was not a sub-tuple pattern so lower it normally. elems.push(self.lower_pat(pat)); } diff --git a/src/test/ui/issues/issue-72574-1.rs b/src/test/ui/issues/issue-72574-1.rs new file mode 100644 index 0000000000000..efbb0bfb1508f --- /dev/null +++ b/src/test/ui/issues/issue-72574-1.rs @@ -0,0 +1,8 @@ +fn main() { + let x = (1, 2, 3); + match x { + (_a, _x @ ..) => {} + _ => {} + } +} +//~^^^^ ERROR `_x @` is not allowed in a tuple diff --git a/src/test/ui/issues/issue-72574-1.stderr b/src/test/ui/issues/issue-72574-1.stderr new file mode 100644 index 0000000000000..329f7d008d498 --- /dev/null +++ b/src/test/ui/issues/issue-72574-1.stderr @@ -0,0 +1,14 @@ +error: `_x @` is not allowed in a tuple + --> $DIR/issue-72574-1.rs:4:14 + | +LL | (_a, _x @ ..) => {} + | ^^^^^^^ this is only allowed in slice patterns + | + = help: remove this and bind each tuple field independently +help: if you don't need to use the contents of _x, discard the tuple's remaining fields + | +LL | (_a, ..) => {} + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-72574-2.rs b/src/test/ui/issues/issue-72574-2.rs new file mode 100644 index 0000000000000..0c8f6fcc50889 --- /dev/null +++ b/src/test/ui/issues/issue-72574-2.rs @@ -0,0 +1,10 @@ +struct Binder(i32, i32, i32); + +fn main() { + let x = Binder(1, 2, 3); + match x { + Binder(_a, _x @ ..) => {} + _ => {} + } +} +//~^^^^ ERROR `_x @` is not allowed in a tuple struct diff --git a/src/test/ui/issues/issue-72574-2.stderr b/src/test/ui/issues/issue-72574-2.stderr new file mode 100644 index 0000000000000..6faa57bcca6b1 --- /dev/null +++ b/src/test/ui/issues/issue-72574-2.stderr @@ -0,0 +1,14 @@ +error: `_x @` is not allowed in a tuple struct + --> $DIR/issue-72574-2.rs:6:20 + | +LL | Binder(_a, _x @ ..) => {} + | ^^^^^^^ this is only allowed in slice patterns + | + = help: remove this and bind each tuple field independently +help: if you don't need to use the contents of _x, discard the tuple's remaining fields + | +LL | Binder(_a, ..) => {} + | ^^ + +error: aborting due to previous error + From 16469a123e45b15b5e520ad59aae6b9a840f71bb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 29 May 2020 13:42:31 -0700 Subject: [PATCH 439/695] Update compiler-builtins Pulls in a fix for #72758, more details on the linked issue. [Crate changes included here][changes] [changes]: https://github.com/rust-lang/compiler-builtins/compare/0.1.28...0.1.31 --- Cargo.lock | 4 ++-- src/libstd/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index feb9ac96bd047..2316cc72dc9c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -631,9 +631,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439a6fab343b1dab347823537734a5cd4ae6ae2000b465ab886f64cdb723bd14" +checksum = "702af8463c84fd83dd76a307ebd47ab3cc866e847bebd4a1deeb6bcc4a658327" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 077ca2a2faa7e..39d786e59976c 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -20,7 +20,7 @@ panic_unwind = { path = "../libpanic_unwind", optional = true } panic_abort = { path = "../libpanic_abort" } core = { path = "../libcore" } libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.16" } +compiler_builtins = { version = "0.1.31" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] } From b92cc8a08d74fb412bc444a4361df51b0c95401c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 29 May 2020 22:46:05 +0200 Subject: [PATCH 440/695] add testcase that no longer ICEs Fixes #3969 --- tests/ui/crashes/ice-3969.rs | 51 ++++++++++++++++++++++++++++++++ tests/ui/crashes/ice-3969.stderr | 22 ++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/ui/crashes/ice-3969.rs create mode 100644 tests/ui/crashes/ice-3969.stderr diff --git a/tests/ui/crashes/ice-3969.rs b/tests/ui/crashes/ice-3969.rs new file mode 100644 index 0000000000000..4feab7910b744 --- /dev/null +++ b/tests/ui/crashes/ice-3969.rs @@ -0,0 +1,51 @@ +// https://github.com/rust-lang/rust-clippy/issues/3969 +// used to crash: error: internal compiler error: +// src/librustc_traits/normalize_erasing_regions.rs:43: could not fully normalize `::Item test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs + +// Check that tautalogically false bounds are accepted, and are used +// in type inference. +#![feature(trivial_bounds)] +#![allow(unused)] + +trait A {} + +impl A for i32 {} + +struct Dst { + x: X, +} + +struct TwoStrs(str, str) +where + str: Sized; + +fn unsized_local() +where + for<'a> Dst: Sized, +{ + let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); +} + +fn return_str() -> str +where + str: Sized, +{ + *"Sized".to_string().into_boxed_str() +} + +fn use_op(s: String) -> String +where + String: ::std::ops::Neg, +{ + -s +} + +fn use_for() +where + i32: Iterator, +{ + for _ in 2i32 {} +} + +fn main() {} diff --git a/tests/ui/crashes/ice-3969.stderr b/tests/ui/crashes/ice-3969.stderr new file mode 100644 index 0000000000000..923db0664a714 --- /dev/null +++ b/tests/ui/crashes/ice-3969.stderr @@ -0,0 +1,22 @@ +error: trait objects without an explicit `dyn` are deprecated + --> $DIR/ice-3969.rs:25:17 + | +LL | for<'a> Dst: Sized, + | ^^^^^^ help: use `dyn`: `dyn A + 'a` + | + = note: `-D bare-trait-objects` implied by `-D warnings` + +error: trait objects without an explicit `dyn` are deprecated + --> $DIR/ice-3969.rs:27:16 + | +LL | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); + | ^ help: use `dyn`: `dyn A` + +error: trait objects without an explicit `dyn` are deprecated + --> $DIR/ice-3969.rs:27:57 + | +LL | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); + | ^ help: use `dyn`: `dyn A` + +error: aborting due to 3 previous errors + From d1e3898bd5d830c29602067ffdb87639f99f0862 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Fri, 29 May 2020 23:41:46 +0200 Subject: [PATCH 441/695] Added the documentation for the 'use' keyword --- src/libstd/keyword_docs.rs | 58 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 6fbb0139b0eca..f74ee6a3e9b00 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1213,9 +1213,63 @@ mod unsafe_keyword {} // /// Import or rename items from other crates or modules. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// Usually a `use` keyword is used to shorten the path required to refer to a module item. +/// The keyword may appear in modules, blocks and even functions, usually at the top. +/// +/// The most basic usage of the keyword is `use path::to::item;`, +/// though a number of convenient shortcuts are supported: +/// +/// * Simultaneously binding a list of paths with a common prefix, +/// using the glob-like brace syntax use `a::b::{c, d, e::f, g::h::i};` +/// * Simultaneously binding a list of paths with a common prefix and their common parent module, +/// using the [`self`] keyword, such as `use a::b::{self, c, d::e};` +/// * Rebinding the target name as a new local name, using the syntax `use p::q::r as x;`. +/// This can also be used with the last two features: `use a::b::{self as ab, c as abc}`. +/// * Binding all paths matching a given prefix, +/// using the asterisk wildcard syntax `use a::b::*;`. +/// * Nesting groups of the previous features multiple times, +/// such as `use a::b::{self as ab, c, d::{*, e::f}};` +/// * Reexporting with visibility modifiers such as `pub use a::b;` +/// * Importing with `_` to only import the methods of the item without binding it to a name +/// (to avoid conflict for example): `use ::std::io::Read as _;`. +/// +/// Using path qualifiers like [`crate`], [`super`] or [`self`] is supported: `use crate::a::b;`. +/// +/// Note that when the wildcard `*` is used on a type, it does not import its methods (though +/// for `enum`s it imports the variants, as shown in the example below). +/// +/// ```compile_fail +/// # fn main() { +/// enum ExampleEnum { +/// VariantA, +/// VariantB, +/// } /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// impl ExampleEnum { +/// fn new() -> Self { +/// Self::VariantA +/// } +/// } +/// +/// use ExampleEnum::*; +/// +/// // Compiles. +/// let _ = VariantA; +/// +/// // Does not compile ! +/// let n = new(); +/// # } +/// ``` +/// +/// For more information on `use` and paths in general, see the [Reference]. +/// +/// The differences about paths and the `use` keyword between the 2015 and 2018 editions +/// can also be found in the [Reference]. +/// +/// [`crate`]: keyword.crate.html +/// [`self`]: keyword.self.html +/// [`super`]: keyword.super.html +/// [Reference]: ../reference/items/use-declarations.html mod use_keyword {} #[doc(keyword = "where")] From c4b6224ea46f57bb59df8d321d8f40e7f2900423 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 00:02:30 +0200 Subject: [PATCH 442/695] more type sanity checks in Miri --- src/librustc_mir/interpret/operand.rs | 12 ++++++++++-- src/librustc_mir/interpret/place.rs | 8 ++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index f546f6236d777..3cfc331ef8c4e 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -15,8 +15,8 @@ use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ - from_known_layout, ConstValue, GlobalId, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, - Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, + from_known_layout, mir_assign_valid_types, ConstValue, GlobalId, InterpCx, InterpResult, + MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -469,6 +469,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .try_fold(base_op, |op, elem| self.operand_projection(op, elem))?; trace!("eval_place_to_op: got {:?}", *op); + // Sanity-check the type we ended up with. + debug_assert!(mir_assign_valid_types( + *self.tcx, + self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( + place.ty(&self.frame().body.local_decls, *self.tcx).ty + ))?, + op.layout, + )); Ok(op) } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 6dadb8e4c67f4..f5e7c1a4823cf 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -638,6 +638,14 @@ where } self.dump_place(place_ty.place); + // Sanity-check the type we ended up with. + debug_assert!(mir_assign_valid_types( + *self.tcx, + self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions( + place.ty(&self.frame().body.local_decls, *self.tcx).ty + ))?, + place_ty.layout, + )); Ok(place_ty) } From 6700e186883a83008963d1fdba23eff2b1713e56 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 12 May 2020 20:09:55 -0700 Subject: [PATCH 443/695] Add Extend::{extend_one,extend_reserve} This adds new optional methods on `Extend`: `extend_one` add a single element to the collection, and `extend_reserve` pre-allocates space for the predicted number of incoming elements. These are used in `Iterator` for `partition` and `unzip` as they shuffle elements one-at-a-time into their respective collections. --- src/liballoc/collections/binary_heap.rs | 20 ++++++++++++++ src/liballoc/collections/btree/map.rs | 10 +++++++ src/liballoc/collections/btree/set.rs | 10 +++++++ src/liballoc/collections/linked_list.rs | 10 +++++++ src/liballoc/collections/vec_deque.rs | 20 ++++++++++++++ src/liballoc/lib.rs | 1 + src/liballoc/string.rs | 35 ++++++++++++++++++++++++ src/liballoc/vec.rs | 20 ++++++++++++++ src/libcore/iter/traits/collect.rs | 15 +++++++++- src/libcore/iter/traits/iterator.rs | 14 +++++++--- src/librustc_data_structures/lib.rs | 1 + src/librustc_data_structures/thin_vec.rs | 14 ++++++++++ src/librustc_index/lib.rs | 1 + src/librustc_index/vec.rs | 10 +++++++ src/librustc_infer/lib.rs | 1 + src/librustc_infer/traits/util.rs | 8 ++++++ src/libstd/collections/hash/map.rs | 29 ++++++++++++++++++++ src/libstd/collections/hash/set.rs | 20 ++++++++++++++ src/libstd/lib.rs | 1 + src/libstd/path.rs | 5 ++++ src/libstd/sys_common/wtf8.rs | 11 ++++++++ 21 files changed, 251 insertions(+), 5 deletions(-) diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index a3ef998918433..c2fe4691b34c0 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -1376,6 +1376,16 @@ impl Extend for BinaryHeap { fn extend>(&mut self, iter: I) { >::spec_extend(self, iter); } + + #[inline] + fn extend_one(&mut self, item: T) { + self.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } impl> SpecExtend for BinaryHeap { @@ -1406,4 +1416,14 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &item: &'a T) { + self.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index c6cb39b1bf511..fa1c09d9ece87 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1901,6 +1901,11 @@ impl Extend<(K, V)> for BTreeMap { self.insert(k, v); }); } + + #[inline] + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -1908,6 +1913,11 @@ impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); } + + #[inline] + fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) { + self.insert(k, v); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index dee5fb878ff2a..525ef38c32fa2 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -1152,6 +1152,11 @@ impl Extend for BTreeSet { self.insert(elem); }); } + + #[inline] + fn extend_one(&mut self, elem: T) { + self.insert(elem); + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -1159,6 +1164,11 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &elem: &'a T) { + self.insert(elem); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index cc0f07b822741..85f2505f756aa 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -1748,6 +1748,11 @@ impl Extend for LinkedList { fn extend>(&mut self, iter: I) { >::spec_extend(self, iter); } + + #[inline] + fn extend_one(&mut self, elem: T) { + self.push_back(elem); + } } impl SpecExtend for LinkedList { @@ -1767,6 +1772,11 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &elem: &'a T) { + self.push_back(elem); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 540649c61b332..ae54d3971baac 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -2881,6 +2881,16 @@ impl Extend for VecDeque { } } } + + #[inline] + fn extend_one(&mut self, elem: A) { + self.push_back(elem); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -2888,6 +2898,16 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &elem: &T) { + self.push_back(elem); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 7aaa91ee10d97..9bcfc9457f50e 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -93,6 +93,7 @@ #![feature(container_error_extra)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] +#![feature(extend_one)] #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index f3fe1adebb141..0378ff5362a8b 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1799,6 +1799,16 @@ impl Extend for String { self.reserve(lower_bound); iterator.for_each(move |c| self.push(c)); } + + #[inline] + fn extend_one(&mut self, c: char) { + self.push(c); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -1806,6 +1816,16 @@ impl<'a> Extend<&'a char> for String { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &c: &'a char) { + self.push(c); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1813,6 +1833,11 @@ impl<'a> Extend<&'a str> for String { fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(s)); } + + #[inline] + fn extend_one(&mut self, s: &'a str) { + self.push_str(s); + } } #[stable(feature = "extend_string", since = "1.4.0")] @@ -1820,6 +1845,11 @@ impl Extend for String { fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(&s)); } + + #[inline] + fn extend_one(&mut self, s: String) { + self.push_str(&s); + } } #[stable(feature = "herd_cows", since = "1.19.0")] @@ -1827,6 +1857,11 @@ impl<'a> Extend> for String { fn extend>>(&mut self, iter: I) { iter.into_iter().for_each(move |s| self.push_str(&s)); } + + #[inline] + fn extend_one(&mut self, s: Cow<'a, str>) { + self.push_str(&s); + } } /// A convenience impl that delegates to the impl for `&str`. diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index d26cd77aae4b7..42fb1f8c737b3 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2045,6 +2045,16 @@ impl Extend for Vec { fn extend>(&mut self, iter: I) { >::spec_extend(self, iter.into_iter()) } + + #[inline] + fn extend_one(&mut self, item: T) { + self.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } // Specialization trait used for Vec::from_iter and Vec::extend @@ -2316,6 +2326,16 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { self.spec_extend(iter.into_iter()) } + + #[inline] + fn extend_one(&mut self, &item: &'a T) { + self.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.reserve(additional); + } } macro_rules! __impl_slice_eq1 { diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index f21ab8dbc3737..da859db545d7e 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -322,7 +322,7 @@ impl IntoIterator for I { pub trait Extend { /// Extends a collection with the contents of an iterator. /// - /// As this is the only method for this trait, the [trait-level] docs + /// As this is the only required method for this trait, the [trait-level] docs /// contain more details. /// /// [trait-level]: trait.Extend.html @@ -341,6 +341,18 @@ pub trait Extend { /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn extend>(&mut self, iter: T); + + /// Extends a collection with exactly one element. + #[unstable(feature = "extend_one", issue = "none")] + fn extend_one(&mut self, item: A) { + self.extend(Some(item)); + } + + /// Reserves capacity in a collection for the given number of additional elements. + /// + /// The default implementation does nothing. + #[unstable(feature = "extend_one", issue = "none")] + fn extend_reserve(&mut self, _additional: usize) {} } #[stable(feature = "extend_for_unit", since = "1.28.0")] @@ -348,4 +360,5 @@ impl Extend<()> for () { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(drop) } + fn extend_one(&mut self, _item: ()) {} } diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 7f081f732fd58..a10b34d931d10 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -1711,9 +1711,9 @@ pub trait Iterator { ) -> impl FnMut((), T) + 'a { move |(), x| { if f(&x) { - left.extend(Some(x)); + left.extend_one(x); } else { - right.extend(Some(x)); + right.extend_one(x); } } } @@ -2686,14 +2686,20 @@ pub trait Iterator { us: &'a mut impl Extend, ) -> impl FnMut((), (A, B)) + 'a { move |(), (t, u)| { - ts.extend(Some(t)); - us.extend(Some(u)); + ts.extend_one(t); + us.extend_one(u); } } let mut ts: FromA = Default::default(); let mut us: FromB = Default::default(); + let (lower_bound, _) = self.size_hint(); + if lower_bound > 0 { + ts.extend_reserve(lower_bound); + us.extend_reserve(lower_bound); + } + self.fold((), extend(&mut ts, &mut us)); (ts, us) diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 7ee60176dbead..0b2e7cda1b4cc 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -22,6 +22,7 @@ #![feature(test)] #![feature(associated_type_bounds)] #![feature(thread_id_value)] +#![feature(extend_one)] #![allow(rustc::default_hash_types)] #[macro_use] diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs index 2befc0aa50487..43002178eb971 100644 --- a/src/librustc_data_structures/thin_vec.rs +++ b/src/librustc_data_structures/thin_vec.rs @@ -53,6 +53,20 @@ impl Extend for ThinVec { ThinVec(None) => *self = iter.into_iter().collect::>().into(), } } + + fn extend_one(&mut self, item: T) { + match *self { + ThinVec(Some(ref mut vec)) => vec.push(item), + ThinVec(None) => *self = vec![item].into(), + } + } + + fn extend_reserve(&mut self, additional: usize) { + match *self { + ThinVec(Some(ref mut vec)) => vec.reserve(additional), + ThinVec(None) => *self = Vec::with_capacity(additional).into(), + } + } } impl, CTX> HashStable for ThinVec { diff --git a/src/librustc_index/lib.rs b/src/librustc_index/lib.rs index e8aa1a209e929..3effc41645011 100644 --- a/src/librustc_index/lib.rs +++ b/src/librustc_index/lib.rs @@ -2,6 +2,7 @@ #![feature(const_if_match)] #![feature(const_fn)] #![feature(const_panic)] +#![feature(extend_one)] #![feature(unboxed_closures)] #![feature(test)] #![feature(fn_traits)] diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs index 67dcea58cf82b..4dde33283f575 100644 --- a/src/librustc_index/vec.rs +++ b/src/librustc_index/vec.rs @@ -736,6 +736,16 @@ impl Extend for IndexVec { fn extend>(&mut self, iter: J) { self.raw.extend(iter); } + + #[inline] + fn extend_one(&mut self, item: T) { + self.raw.push(item); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.raw.reserve(additional); + } } impl FromIterator for IndexVec { diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs index 28d42cea6d300..ed04ee02b7203 100644 --- a/src/librustc_infer/lib.rs +++ b/src/librustc_infer/lib.rs @@ -16,6 +16,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(extend_one)] #![feature(never_type)] #![feature(or_patterns)] #![feature(range_is_empty)] diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 17b7b4e680f5e..8081cac0067f1 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -81,6 +81,14 @@ impl Extend> for PredicateSet<'tcx> { self.insert(pred); } } + + fn extend_one(&mut self, pred: ty::Predicate<'tcx>) { + self.insert(pred); + } + + fn extend_reserve(&mut self, additional: usize) { + Extend::>::extend_reserve(&mut self.set, additional); + } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 56cf9be339194..a51f1998e4452 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2426,6 +2426,24 @@ where fn extend>(&mut self, iter: T) { self.base.extend(iter) } + + #[inline] + fn extend_one(&mut self, (k, v): (K, V)) { + self.base.insert(k, v); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + // self.base.extend_reserve(additional); + // FIXME: hashbrown should implement this method. + // But until then, use the same reservation logic: + + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if self.is_empty() { additional } else { (additional + 1) / 2 }; + self.base.reserve(reserve); + } } #[stable(feature = "hash_extend_copy", since = "1.4.0")] @@ -2439,6 +2457,17 @@ where fn extend>(&mut self, iter: T) { self.base.extend(iter) } + + #[inline] + fn extend_one(&mut self, (&k, &v): (&'a K, &'a V)) { + self.base.insert(k, v); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + // self.base.extend_reserve(additional); + Extend::<(K, V)>::extend_reserve(self, additional) + } } /// `RandomState` is the default state for [`HashMap`] types. diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ca06457291cae..cb2f829803b85 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -970,6 +970,16 @@ where fn extend>(&mut self, iter: I) { self.map.extend(iter.into_iter().map(|k| (k, ()))); } + + #[inline] + fn extend_one(&mut self, item: T) { + self.map.insert(item, ()); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + self.map.extend_reserve(additional); + } } #[stable(feature = "hash_extend_copy", since = "1.4.0")] @@ -982,6 +992,16 @@ where fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } + + #[inline] + fn extend_one(&mut self, &item: &'a T) { + self.map.insert(item, ()); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + Extend::::extend_reserve(self, additional) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 72dfe2937f491..9ddaa100c0e9d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -263,6 +263,7 @@ #![feature(duration_constants)] #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] +#![feature(extend_one)] #![feature(external_doc)] #![feature(fn_traits)] #![feature(format_args_nl)] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 0fe5451bb9564..8ff7508ba6457 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1534,6 +1534,11 @@ impl> iter::Extend/src exists before processing test --- tests/compile-test.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 7bd5f09f333dd..194354b291fda 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -181,8 +181,15 @@ fn run_ui_cargo(config: &mut compiletest::Config) { } let src_path = case.path().join("src"); - env::set_current_dir(&src_path)?; + // When switching between branches, if the previous branch had a test + // that the current branch does not have, the directory is not removed + // because an ignored Cargo.lock file exists. + if !src_path.exists() { + continue; + } + + env::set_current_dir(&src_path)?; for file in fs::read_dir(&src_path)? { let file = file?; if file.file_type()?.is_dir() { From 0a71ba22430c5ca9ca19db1ee03c378e8b1da73c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 31 May 2020 14:51:08 -0400 Subject: [PATCH 518/695] Fix release notes for niche initialization change MaybeUninit is not affected by the linked PR. --- RELEASES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 7cba27e134a78..100993bb75cec 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -100,8 +100,8 @@ Compatibility Notes source file rather than the previous format of ``.][70969] **Note:** this may not point a file that actually exists on the user's system. - [The minimum required external LLVM version has been bumped to LLVM 8.][71147] -- [`mem::{zeroed, uninitialised, MaybeUninit}` will now panic when used with types - that do not allow zero initialization such as `NonZeroU8`.][66059] This was +- [`mem::{zeroed, uninitialised}` will now panic when used with types that do + not allow zero initialization such as `NonZeroU8`.][66059] This was previously a warning. - [In 1.45.0 (the next release) converting a `f64` to `u32` using the `as` operator has been defined as a saturating operation.][71269] This was previously From 7e843515d9525b6389c3fc1bcfa6ae046c1351dc Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Thu, 14 May 2020 15:06:05 -0700 Subject: [PATCH 519/695] Created lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 4 ++++ clippy_lints/src/sort_by_key_reverse.rs | 28 +++++++++++++++++++++++++ src/lintlist/mod.rs | 7 +++++++ tests/ui/sort_by_key_reverse.rs | 5 +++++ 5 files changed, 45 insertions(+) create mode 100644 clippy_lints/src/sort_by_key_reverse.rs create mode 100644 tests/ui/sort_by_key_reverse.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f7dae3dcfff0f..c00f84bdb8570 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1555,6 +1555,7 @@ Released 2018-09-13 [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization +[`sort_by_key_reverse`]: https://rust-lang.github.io/rust-clippy/master/index.html#sort_by_key_reverse [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 38cfa212d9f48..f51855badff81 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -304,6 +304,7 @@ mod serde_api; mod shadow; mod single_component_path_imports; mod slow_vector_initialization; +mod sort_by_key_reverse; mod strings; mod suspicious_trait_impl; mod swap; @@ -779,6 +780,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_UNRELATED, &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, + &sort_by_key_reverse::SORT_BY_KEY_REVERSE, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, &strings::STRING_LIT_AS_BYTES, @@ -1391,6 +1393,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), + LintId::of(&sort_by_key_reverse::SORT_BY_KEY_REVERSE), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), @@ -1592,6 +1595,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), + LintId::of(&sort_by_key_reverse::SORT_BY_KEY_REVERSE), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), diff --git a/clippy_lints/src/sort_by_key_reverse.rs b/clippy_lints/src/sort_by_key_reverse.rs new file mode 100644 index 0000000000000..65830afd0f8d0 --- /dev/null +++ b/clippy_lints/src/sort_by_key_reverse.rs @@ -0,0 +1,28 @@ +use rustc_lint::{LateLintPass, LateContext}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_hir::*; + +declare_clippy_lint! { + /// **What it does:** + /// + /// **Why is this bad?** + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // example code where clippy issues a warning + /// ``` + /// Use instead: + /// ```rust + /// // example code which does not raise clippy warning + /// ``` + pub SORT_BY_KEY_REVERSE, + complexity, + "default lint description" +} + +declare_lint_pass!(SortByKeyReverse => [SORT_BY_KEY_REVERSE]); + +impl LateLintPass<'_, '_> for SortByKeyReverse {} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 69578732898fc..1b82f34c8634d 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1984,6 +1984,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "slow_vector_initialization", }, + Lint { + name: "sort_by_key_reverse", + group: "complexity", + desc: "default lint description", + deprecation: None, + module: "sort_by_key_reverse", + }, Lint { name: "string_add", group: "restriction", diff --git a/tests/ui/sort_by_key_reverse.rs b/tests/ui/sort_by_key_reverse.rs new file mode 100644 index 0000000000000..2338dc6e5940b --- /dev/null +++ b/tests/ui/sort_by_key_reverse.rs @@ -0,0 +1,5 @@ +#![warn(clippy::sort_by_key_reverse)] + +fn main() { + // test code goes here +} From 24847ea53e332853597aca2c7dfe48a9f3be1de8 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Sat, 16 May 2020 13:50:33 -0700 Subject: [PATCH 520/695] Attempted start at sort_by_key_reverse lint --- clippy_lints/src/sort_by_key_reverse.rs | 71 +++++++++++++++++++++++-- src/lintlist/mod.rs | 2 +- tests/ui/sort_by_key_reverse.fixed | 0 tests/ui/sort_by_key_reverse.rs | 3 +- tests/ui/sort_by_key_reverse.stderr | 0 5 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 tests/ui/sort_by_key_reverse.fixed create mode 100644 tests/ui/sort_by_key_reverse.stderr diff --git a/clippy_lints/src/sort_by_key_reverse.rs b/clippy_lints/src/sort_by_key_reverse.rs index 65830afd0f8d0..7d7097a81253e 100644 --- a/clippy_lints/src/sort_by_key_reverse.rs +++ b/clippy_lints/src/sort_by_key_reverse.rs @@ -1,28 +1,91 @@ +use crate::utils::{match_type, span_lint_and_sugg}; +use crate::utils::paths; +use crate::utils::sugg::Sugg; +use if_chain::if_chain; +use rustc_errors::Applicability; use rustc_lint::{LateLintPass, LateContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_hir::*; declare_clippy_lint! { /// **What it does:** + /// Detects when people use `Vec::sort_by` and pass in a function + /// which compares the second argument to the first. /// /// **Why is this bad?** + /// It is more clear to use `Vec::sort_by_key` and `std::cmp::Reverse` /// /// **Known problems:** None. /// /// **Example:** /// /// ```rust - /// // example code where clippy issues a warning + /// vec.sort_by(|a, b| b.foo().cmp(&a.foo())); /// ``` /// Use instead: /// ```rust - /// // example code which does not raise clippy warning + /// vec.sort_by_key(|e| Reverse(e.foo())); /// ``` pub SORT_BY_KEY_REVERSE, complexity, - "default lint description" + "Use of `Vec::sort_by` when `Vec::sort_by_key` would be clearer" } declare_lint_pass!(SortByKeyReverse => [SORT_BY_KEY_REVERSE]); -impl LateLintPass<'_, '_> for SortByKeyReverse {} +struct LintTrigger { + vec_name: String, + closure_arg: String, + closure_reverse_body: String, + unstable: bool, +} + +fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option { + if_chain! { + if let ExprKind::MethodCall(name_ident, _, args) = &expr.kind; + if let name = name_ident.ident.name.to_ident_string(); + if name == "sort_by" || name == "sort_unstable_by"; + if let [vec, Expr { kind: ExprKind::Closure(_, closure_decl, closure_body_id, _, _), .. }] = args; + if closure_decl.inputs.len() == 2; + if match_type(cx, &cx.tables.expr_ty(vec), &paths::VEC); + then { + let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); + let unstable = name == "sort_unstable_by"; + Some(LintTrigger { vec_name, unstable, closure_arg: "e".to_string(), closure_reverse_body: "e".to_string() }) + } else { + None + } + } +} + +impl LateLintPass<'_, '_> for SortByKeyReverse { + fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { + println!("{:?}", expr); + span_lint_and_sugg( + cx, + SORT_BY_KEY_REVERSE, + expr.span, + "use Vec::sort_by_key here instead", + "try", + String::from("being a better person"), + Applicability::MachineApplicable, + ); + if let Some(trigger) = detect_lint(cx, expr) { + span_lint_and_sugg( + cx, + SORT_BY_KEY_REVERSE, + expr.span, + "use Vec::sort_by_key here instead", + "try", + format!( + "{}.sort{}_by_key(|{}| Reverse({}))", + trigger.vec_name, + if trigger.unstable { "_unstable" } else { "" }, + trigger.closure_arg, + trigger.closure_reverse_body, + ), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 1b82f34c8634d..b5d9ef0110e25 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1987,7 +1987,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "sort_by_key_reverse", group: "complexity", - desc: "default lint description", + desc: "Use of `Vec::sort_by` when `Vec::sort_by_key` would be clearer", deprecation: None, module: "sort_by_key_reverse", }, diff --git a/tests/ui/sort_by_key_reverse.fixed b/tests/ui/sort_by_key_reverse.fixed new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tests/ui/sort_by_key_reverse.rs b/tests/ui/sort_by_key_reverse.rs index 2338dc6e5940b..c0350f243c7be 100644 --- a/tests/ui/sort_by_key_reverse.rs +++ b/tests/ui/sort_by_key_reverse.rs @@ -1,5 +1,6 @@ #![warn(clippy::sort_by_key_reverse)] fn main() { - // test code goes here + let mut vec = vec![3, 6, 1, 2, 5]; + vec.sort_by(|a, b| b.cmp(a)); } diff --git a/tests/ui/sort_by_key_reverse.stderr b/tests/ui/sort_by_key_reverse.stderr new file mode 100644 index 0000000000000..e69de29bb2d1d From 8590ab4d46de4eb43e7ebd42cb2f13b0064573e6 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Mon, 18 May 2020 21:48:35 -0700 Subject: [PATCH 521/695] More progress towards sort_by_key_reverse lint --- clippy_lints/src/lib.rs | 1 + clippy_lints/src/sort_by_key_reverse.rs | 131 ++++++++++++++++++++---- tests/ui/sort_by_key_reverse.fixed | 9 ++ tests/ui/sort_by_key_reverse.rs | 5 +- tests/ui/sort_by_key_reverse.stderr | 22 ++++ 5 files changed, 149 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f51855badff81..e7a4c1ecaa954 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -998,6 +998,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast); store.register_late_pass(|| box redundant_clone::RedundantClone); store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); + store.register_late_pass(|| box sort_by_key_reverse::SortByKeyReverse); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); diff --git a/clippy_lints/src/sort_by_key_reverse.rs b/clippy_lints/src/sort_by_key_reverse.rs index 7d7097a81253e..d70391999a023 100644 --- a/clippy_lints/src/sort_by_key_reverse.rs +++ b/clippy_lints/src/sort_by_key_reverse.rs @@ -1,11 +1,12 @@ -use crate::utils::{match_type, span_lint_and_sugg}; +use crate::utils; use crate::utils::paths; use crate::utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_lint::{LateLintPass, LateContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// **What it does:** @@ -40,18 +41,122 @@ struct LintTrigger { unstable: bool, } +/// Detect if the two expressions are mirrored (identical, except one +/// contains a and the other replaces it with b) +fn mirrored_exprs(cx: &LateContext<'_, '_>, a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { + match (&a_expr.kind, &b_expr.kind) { + // Two boxes with mirrored contents + (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + // Two arrays with mirrored contents + (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) + => left_exprs.iter().zip(right_exprs.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + // The two exprs are function calls. + // Check to see that the function itself and its arguments are mirrored + (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) + => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + && left_args.iter().zip(right_args.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + // The two exprs are method calls. + // Check to see that the function is the same and the arguments are mirrored + // This is enough because the receiver of the method is listed in the arguments + (ExprKind::MethodCall(left_segment, _, left_args), ExprKind::MethodCall(right_segment, _, right_args)) + => left_segment.ident == right_segment.ident + && left_args.iter().zip(right_args.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + // Two tuples with mirrored contents + (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) + => left_exprs.iter().zip(right_exprs.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + // Two binary ops, which are the same operation and which have mirrored arguments + (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) + => left_op.node == right_op.node + && mirrored_exprs(cx, left_left, a_ident, right_left, b_ident) + && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident), + // Two unary ops, which are the same operation and which have the same argument + (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) + => left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + // The two exprs are literals of some kind + (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node, + (ExprKind::Cast(left_expr, _), ExprKind::Cast(right_expr, _)) + => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (ExprKind::DropTemps(left), ExprKind::DropTemps(right)) => mirrored_exprs(cx, left, a_ident, right, b_ident), + (ExprKind::Block(left, _), ExprKind::Block(right, _)) => mirrored_blocks(cx, left, a_ident, right, b_ident), + (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) + => left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident), + // The two exprs are `a` and `b`, directly + (ExprKind::Path(QPath::Resolved(_, Path { segments: &[PathSegment { ident: left_ident, .. }], .. },)), + ExprKind::Path(QPath::Resolved(_, Path { segments: &[PathSegment { ident: right_ident, .. }], .. },)), + ) => &left_ident == a_ident && &right_ident == b_ident, + // The two exprs are Paths to the same name (which is neither a nor b) + (ExprKind::Path(QPath::Resolved(_, Path { segments: left_segments, .. })), + ExprKind::Path(QPath::Resolved(_, Path { segments: right_segments, .. }))) + => left_segments.iter().zip(right_segments.iter()).all(|(left, right)| left.ident == right.ident) + && left_segments.iter().all(|seg| &seg.ident != a_ident && &seg.ident != b_ident), + // Matching expressions, but one or both is borrowed + (ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), ExprKind::AddrOf(right_kind, Mutability::Not, right_expr)) + => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) + => mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident), + (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) + => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident), + // _ => false, + (left, right) => { + println!("{:?}\n{:?}", left, right); + false + }, + } +} + +/// Detect if the two blocks are mirrored (identical, except one +/// contains a and the other replaces it with b) +fn mirrored_blocks(cx: &LateContext<'_, '_>, a_block: &Block<'_>, a_ident: &Ident, b_block: &Block<'_>, b_ident: &Ident) -> bool { + match (a_block, b_block) { + (Block { stmts: left_stmts, expr: left_expr, .. }, + Block { stmts: right_stmts, expr: right_expr, .. }) + => left_stmts.iter().zip(right_stmts.iter()).all(|(left, right)| match (&left.kind, &right.kind) { + (StmtKind::Expr(left_expr), StmtKind::Expr(right_expr)) => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (StmtKind::Semi(left_expr), StmtKind::Semi(right_expr)) => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (StmtKind::Item(left_item), StmtKind::Item(right_item)) => left_item.id == right_item.id, + (StmtKind::Local(left), StmtKind::Local(right)) => mirrored_locals(cx, left, a_ident, right, b_ident), + _ => false, + }) && match (left_expr, right_expr) { + (None, None) => true, + (Some(left), Some(right)) => mirrored_exprs(cx, left, a_ident, right, b_ident), + _ => false, + }, + } +} + +/// Check that the two "Local"s (let statements) are equal +fn mirrored_locals(cx: &LateContext<'_, '_>, a_local: &Local<'_>, a_ident: &Ident, b_local: &Local<'_>, b_ident: &Ident) -> bool { + match (a_local, b_local) { + (Local { pat: left_pat, init: left_expr, .. }, Local { pat: right_pat, init: right_expr, .. }) + => match (left_expr, right_expr) { + (None, None) => true, + (Some(left), Some(right)) => mirrored_exprs(cx, left, a_ident, right, b_ident), + _ => false, + }, + } +} + fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option { if_chain! { if let ExprKind::MethodCall(name_ident, _, args) = &expr.kind; if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; - if let [vec, Expr { kind: ExprKind::Closure(_, closure_decl, closure_body_id, _, _), .. }] = args; - if closure_decl.inputs.len() == 2; - if match_type(cx, &cx.tables.expr_ty(vec), &paths::VEC); + if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; + if utils::match_type(cx, &cx.tables.expr_ty(vec), &paths::VEC); + if let closure_body = cx.tcx.hir().body(*closure_body_id); + if let &[ + Param { pat: Pat { kind: PatKind::Binding(_, _, a_ident, _), .. }, ..}, + Param { pat: Pat { kind: PatKind::Binding(_, _, b_ident, _), .. }, .. } + ] = &closure_body.params; + if let ExprKind::MethodCall(method_path, _, [ref b_expr, ref a_expr]) = &closure_body.value.kind; + if method_path.ident.name.to_ident_string() == "cmp"; + if mirrored_exprs(&cx, &a_expr, &a_ident, &b_expr, &b_ident); then { let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); let unstable = name == "sort_unstable_by"; - Some(LintTrigger { vec_name, unstable, closure_arg: "e".to_string(), closure_reverse_body: "e".to_string() }) + let closure_arg = a_ident.name.to_ident_string(); + let closure_reverse_body = Sugg::hir(cx, &a_expr, "..").to_string(); + Some(LintTrigger { vec_name, unstable, closure_arg, closure_reverse_body }) } else { None } @@ -60,18 +165,8 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option impl LateLintPass<'_, '_> for SortByKeyReverse { fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { - println!("{:?}", expr); - span_lint_and_sugg( - cx, - SORT_BY_KEY_REVERSE, - expr.span, - "use Vec::sort_by_key here instead", - "try", - String::from("being a better person"), - Applicability::MachineApplicable, - ); if let Some(trigger) = detect_lint(cx, expr) { - span_lint_and_sugg( + utils::span_lint_and_sugg( cx, SORT_BY_KEY_REVERSE, expr.span, diff --git a/tests/ui/sort_by_key_reverse.fixed b/tests/ui/sort_by_key_reverse.fixed index e69de29bb2d1d..4b18a073e1add 100644 --- a/tests/ui/sort_by_key_reverse.fixed +++ b/tests/ui/sort_by_key_reverse.fixed @@ -0,0 +1,9 @@ +// run-rustfix +#![warn(clippy::sort_by_key_reverse)] + +fn main() { + let mut vec: Vec = vec![3, 6, 1, 2, 5]; + vec.sort_by_key(|a| Reverse(a)); + vec.sort_by_key(|a| Reverse(&(a+5).abs())); + vec.sort_by_key(|a| Reverse(&-a)); +} diff --git a/tests/ui/sort_by_key_reverse.rs b/tests/ui/sort_by_key_reverse.rs index c0350f243c7be..f4fb70b7b1dcb 100644 --- a/tests/ui/sort_by_key_reverse.rs +++ b/tests/ui/sort_by_key_reverse.rs @@ -1,6 +1,9 @@ +// run-rustfix #![warn(clippy::sort_by_key_reverse)] fn main() { - let mut vec = vec![3, 6, 1, 2, 5]; + let mut vec: Vec = vec![3, 6, 1, 2, 5]; vec.sort_by(|a, b| b.cmp(a)); + vec.sort_by(|a, b| (b + 5).abs().cmp(&(a+5).abs())); + vec.sort_by(|a, b| (-b).cmp(&-a)); } diff --git a/tests/ui/sort_by_key_reverse.stderr b/tests/ui/sort_by_key_reverse.stderr index e69de29bb2d1d..36a28c04b1c55 100644 --- a/tests/ui/sort_by_key_reverse.stderr +++ b/tests/ui/sort_by_key_reverse.stderr @@ -0,0 +1,22 @@ +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key_reverse.rs:6:5 + | +LL | vec.sort_by(|a, b| b.cmp(a)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| Reverse(a))` + | + = note: `-D clippy::sort-by-key-reverse` implied by `-D warnings` + +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key_reverse.rs:7:5 + | +LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a+5).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| Reverse(&(a+5).abs()))` + +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key_reverse.rs:8:5 + | +LL | vec.sort_by(|a, b| (-b).cmp(&-a)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| Reverse(&-a))` + +error: aborting due to 3 previous errors + From 943cb94dce8fca6f3a3f7f011a2a2f9f0a665b97 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Tue, 19 May 2020 22:57:27 -0700 Subject: [PATCH 522/695] Passes all tests now! --- clippy_lints/src/sort_by_key_reverse.rs | 72 ++++++++----------------- tests/ui/sort_by_key_reverse.fixed | 12 +++-- tests/ui/sort_by_key_reverse.rs | 8 ++- tests/ui/sort_by_key_reverse.stderr | 14 ++--- 4 files changed, 45 insertions(+), 61 deletions(-) diff --git a/clippy_lints/src/sort_by_key_reverse.rs b/clippy_lints/src/sort_by_key_reverse.rs index d70391999a023..31629a1dbc1b4 100644 --- a/clippy_lints/src/sort_by_key_reverse.rs +++ b/clippy_lints/src/sort_by_key_reverse.rs @@ -53,8 +53,12 @@ fn mirrored_exprs(cx: &LateContext<'_, '_>, a_expr: &Expr<'_>, a_ident: &Ident, // The two exprs are function calls. // Check to see that the function itself and its arguments are mirrored (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) - => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) - && left_args.iter().zip(right_args.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + => { + // println!("{:?}\n{:?}\n", left_expr, left_args); + // println!("{:?}\n{:?}\n", right_expr, right_args); + mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + && left_args.iter().zip(right_args.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + }, // The two exprs are method calls. // Check to see that the function is the same and the arguments are mirrored // This is enough because the receiver of the method is listed in the arguments @@ -74,21 +78,17 @@ fn mirrored_exprs(cx: &LateContext<'_, '_>, a_expr: &Expr<'_>, a_ident: &Ident, => left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), // The two exprs are literals of some kind (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node, - (ExprKind::Cast(left_expr, _), ExprKind::Cast(right_expr, _)) + (ExprKind::Cast(left_expr, left_ty), ExprKind::Cast(right_expr, right_ty)) => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), (ExprKind::DropTemps(left), ExprKind::DropTemps(right)) => mirrored_exprs(cx, left, a_ident, right, b_ident), - (ExprKind::Block(left, _), ExprKind::Block(right, _)) => mirrored_blocks(cx, left, a_ident, right, b_ident), (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident), - // The two exprs are `a` and `b`, directly - (ExprKind::Path(QPath::Resolved(_, Path { segments: &[PathSegment { ident: left_ident, .. }], .. },)), - ExprKind::Path(QPath::Resolved(_, Path { segments: &[PathSegment { ident: right_ident, .. }], .. },)), - ) => &left_ident == a_ident && &right_ident == b_ident, - // The two exprs are Paths to the same name (which is neither a nor b) + // Two paths: either one is a and the other is b, or they're identical to each other (ExprKind::Path(QPath::Resolved(_, Path { segments: left_segments, .. })), ExprKind::Path(QPath::Resolved(_, Path { segments: right_segments, .. }))) - => left_segments.iter().zip(right_segments.iter()).all(|(left, right)| left.ident == right.ident) - && left_segments.iter().all(|seg| &seg.ident != a_ident && &seg.ident != b_ident), + => (left_segments.iter().zip(right_segments.iter()).all(|(left, right)| left.ident == right.ident) + && left_segments.iter().all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) + || (left_segments.len() == 1 && &left_segments[0].ident == a_ident && right_segments.len() == 1 && &right_segments[0].ident == b_ident), // Matching expressions, but one or both is borrowed (ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), ExprKind::AddrOf(right_kind, Mutability::Not, right_expr)) => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), @@ -96,43 +96,11 @@ fn mirrored_exprs(cx: &LateContext<'_, '_>, a_expr: &Expr<'_>, a_ident: &Ident, => mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident), (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident), - // _ => false, - (left, right) => { - println!("{:?}\n{:?}", left, right); - false - }, - } -} - -/// Detect if the two blocks are mirrored (identical, except one -/// contains a and the other replaces it with b) -fn mirrored_blocks(cx: &LateContext<'_, '_>, a_block: &Block<'_>, a_ident: &Ident, b_block: &Block<'_>, b_ident: &Ident) -> bool { - match (a_block, b_block) { - (Block { stmts: left_stmts, expr: left_expr, .. }, - Block { stmts: right_stmts, expr: right_expr, .. }) - => left_stmts.iter().zip(right_stmts.iter()).all(|(left, right)| match (&left.kind, &right.kind) { - (StmtKind::Expr(left_expr), StmtKind::Expr(right_expr)) => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), - (StmtKind::Semi(left_expr), StmtKind::Semi(right_expr)) => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), - (StmtKind::Item(left_item), StmtKind::Item(right_item)) => left_item.id == right_item.id, - (StmtKind::Local(left), StmtKind::Local(right)) => mirrored_locals(cx, left, a_ident, right, b_ident), - _ => false, - }) && match (left_expr, right_expr) { - (None, None) => true, - (Some(left), Some(right)) => mirrored_exprs(cx, left, a_ident, right, b_ident), - _ => false, - }, - } -} - -/// Check that the two "Local"s (let statements) are equal -fn mirrored_locals(cx: &LateContext<'_, '_>, a_local: &Local<'_>, a_ident: &Ident, b_local: &Local<'_>, b_ident: &Ident) -> bool { - match (a_local, b_local) { - (Local { pat: left_pat, init: left_expr, .. }, Local { pat: right_pat, init: right_expr, .. }) - => match (left_expr, right_expr) { - (None, None) => true, - (Some(left), Some(right)) => mirrored_exprs(cx, left, a_ident, right, b_ident), - _ => false, - }, + _ => false, + // (left, right) => { + // println!("{:?}\n{:?}", left, right); + // false + // }, } } @@ -154,8 +122,12 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option then { let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); let unstable = name == "sort_unstable_by"; - let closure_arg = a_ident.name.to_ident_string(); - let closure_reverse_body = Sugg::hir(cx, &a_expr, "..").to_string(); + let closure_arg = format!("&{}", b_ident.name.to_ident_string()); + let closure_reverse_body = Sugg::hir(cx, &b_expr, "..").to_string(); + // Get rid of parentheses, because they aren't needed anymore + // while closure_reverse_body.chars().next() == Some('(') && closure_reverse_body.chars().last() == Some(')') { + // closure_reverse_body = String::from(&closure_reverse_body[1..closure_reverse_body.len()-1]); + // } Some(LintTrigger { vec_name, unstable, closure_arg, closure_reverse_body }) } else { None diff --git a/tests/ui/sort_by_key_reverse.fixed b/tests/ui/sort_by_key_reverse.fixed index 4b18a073e1add..d536dc385d533 100644 --- a/tests/ui/sort_by_key_reverse.fixed +++ b/tests/ui/sort_by_key_reverse.fixed @@ -1,9 +1,15 @@ // run-rustfix #![warn(clippy::sort_by_key_reverse)] +use std::cmp::Reverse; + +fn id(x: isize) -> isize { + x +} + fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; - vec.sort_by_key(|a| Reverse(a)); - vec.sort_by_key(|a| Reverse(&(a+5).abs())); - vec.sort_by_key(|a| Reverse(&-a)); + vec.sort_by_key(|&b| Reverse(b)); + vec.sort_by_key(|&b| Reverse((b + 5).abs())); + vec.sort_by_key(|&b| Reverse(id(-b))); } diff --git a/tests/ui/sort_by_key_reverse.rs b/tests/ui/sort_by_key_reverse.rs index f4fb70b7b1dcb..9c42d401755ad 100644 --- a/tests/ui/sort_by_key_reverse.rs +++ b/tests/ui/sort_by_key_reverse.rs @@ -1,9 +1,15 @@ // run-rustfix #![warn(clippy::sort_by_key_reverse)] +use std::cmp::Reverse; + +fn id(x: isize) -> isize { + x +} + fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; vec.sort_by(|a, b| b.cmp(a)); vec.sort_by(|a, b| (b + 5).abs().cmp(&(a+5).abs())); - vec.sort_by(|a, b| (-b).cmp(&-a)); + vec.sort_by(|a, b| id(-b).cmp(&id(-a))); } diff --git a/tests/ui/sort_by_key_reverse.stderr b/tests/ui/sort_by_key_reverse.stderr index 36a28c04b1c55..3d26ddae78ad8 100644 --- a/tests/ui/sort_by_key_reverse.stderr +++ b/tests/ui/sort_by_key_reverse.stderr @@ -1,22 +1,22 @@ error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key_reverse.rs:6:5 + --> $DIR/sort_by_key_reverse.rs:12:5 | LL | vec.sort_by(|a, b| b.cmp(a)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| Reverse(a))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))` | = note: `-D clippy::sort-by-key-reverse` implied by `-D warnings` error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key_reverse.rs:7:5 + --> $DIR/sort_by_key_reverse.rs:13:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a+5).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| Reverse(&(a+5).abs()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key_reverse.rs:8:5 + --> $DIR/sort_by_key_reverse.rs:14:5 | -LL | vec.sort_by(|a, b| (-b).cmp(&-a)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| Reverse(&-a))` +LL | vec.sort_by(|a, b| id(-b).cmp(&id(-a))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(id(-b)))` error: aborting due to 3 previous errors From 955a25ee7db234a8ab697176a433070702aabe59 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Wed, 20 May 2020 09:23:00 -0700 Subject: [PATCH 523/695] Added negative test cases and ran cargo dev fmt --- clippy_lints/src/sort_by_key_reverse.rs | 125 ++++++++++++++++-------- tests/ui/sort_by_key_reverse.fixed | 7 ++ tests/ui/sort_by_key_reverse.rs | 9 +- tests/ui/sort_by_key_reverse.stderr | 4 +- 4 files changed, 100 insertions(+), 45 deletions(-) diff --git a/clippy_lints/src/sort_by_key_reverse.rs b/clippy_lints/src/sort_by_key_reverse.rs index 31629a1dbc1b4..ea850955db121 100644 --- a/clippy_lints/src/sort_by_key_reverse.rs +++ b/clippy_lints/src/sort_by_key_reverse.rs @@ -3,7 +3,7 @@ use crate::utils::paths; use crate::utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::*; +use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; @@ -43,64 +43,105 @@ struct LintTrigger { /// Detect if the two expressions are mirrored (identical, except one /// contains a and the other replaces it with b) -fn mirrored_exprs(cx: &LateContext<'_, '_>, a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident: &Ident) -> bool { +fn mirrored_exprs( + cx: &LateContext<'_, '_>, + a_expr: &Expr<'_>, + a_ident: &Ident, + b_expr: &Expr<'_>, + b_ident: &Ident, +) -> bool { match (&a_expr.kind, &b_expr.kind) { // Two boxes with mirrored contents - (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => { + mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + }, // Two arrays with mirrored contents - (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) - => left_exprs.iter().zip(right_exprs.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => left_exprs + .iter() + .zip(right_exprs.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), // The two exprs are function calls. // Check to see that the function itself and its arguments are mirrored - (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) - => { - // println!("{:?}\n{:?}\n", left_expr, left_args); - // println!("{:?}\n{:?}\n", right_expr, right_args); - mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) - && left_args.iter().zip(right_args.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) - }, + (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => { + mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + && left_args + .iter() + .zip(right_args.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + }, // The two exprs are method calls. // Check to see that the function is the same and the arguments are mirrored // This is enough because the receiver of the method is listed in the arguments - (ExprKind::MethodCall(left_segment, _, left_args), ExprKind::MethodCall(right_segment, _, right_args)) - => left_segment.ident == right_segment.ident - && left_args.iter().zip(right_args.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::MethodCall(left_segment, _, left_args), ExprKind::MethodCall(right_segment, _, right_args)) => { + left_segment.ident == right_segment.ident + && left_args + .iter() + .zip(right_args.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)) + }, // Two tuples with mirrored contents - (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) - => left_exprs.iter().zip(right_exprs.iter()).all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), + (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => left_exprs + .iter() + .zip(right_exprs.iter()) + .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)), // Two binary ops, which are the same operation and which have mirrored arguments - (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) - => left_op.node == right_op.node + (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => { + left_op.node == right_op.node && mirrored_exprs(cx, left_left, a_ident, right_left, b_ident) - && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident), + && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident) + }, // Two unary ops, which are the same operation and which have the same argument - (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) - => left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => { + left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident) + }, // The two exprs are literals of some kind (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node, - (ExprKind::Cast(left_expr, left_ty), ExprKind::Cast(right_expr, right_ty)) - => mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), - (ExprKind::DropTemps(left), ExprKind::DropTemps(right)) => mirrored_exprs(cx, left, a_ident, right, b_ident), - (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) - => left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident), + (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(cx, left, a_ident, right, b_ident), + (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => { + mirrored_exprs(cx, left_block, a_ident, right_block, b_ident) + }, + (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => { + left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident) + }, // Two paths: either one is a and the other is b, or they're identical to each other - (ExprKind::Path(QPath::Resolved(_, Path { segments: left_segments, .. })), - ExprKind::Path(QPath::Resolved(_, Path { segments: right_segments, .. }))) - => (left_segments.iter().zip(right_segments.iter()).all(|(left, right)| left.ident == right.ident) - && left_segments.iter().all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) - || (left_segments.len() == 1 && &left_segments[0].ident == a_ident && right_segments.len() == 1 && &right_segments[0].ident == b_ident), + ( + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: left_segments, + .. + }, + )), + ExprKind::Path(QPath::Resolved( + _, + Path { + segments: right_segments, + .. + }, + )), + ) => { + (left_segments + .iter() + .zip(right_segments.iter()) + .all(|(left, right)| left.ident == right.ident) + && left_segments + .iter() + .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident)) + || (left_segments.len() == 1 + && &left_segments[0].ident == a_ident + && right_segments.len() == 1 + && &right_segments[0].ident == b_ident) + }, // Matching expressions, but one or both is borrowed - (ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), ExprKind::AddrOf(right_kind, Mutability::Not, right_expr)) - => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), - (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) - => mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident), - (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) - => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident), + ( + ExprKind::AddrOf(left_kind, Mutability::Not, left_expr), + ExprKind::AddrOf(right_kind, Mutability::Not, right_expr), + ) => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident), + (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => { + mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident) + }, + (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident), _ => false, - // (left, right) => { - // println!("{:?}\n{:?}", left, right); - // false - // }, } } diff --git a/tests/ui/sort_by_key_reverse.fixed b/tests/ui/sort_by_key_reverse.fixed index d536dc385d533..722675a6b71a8 100644 --- a/tests/ui/sort_by_key_reverse.fixed +++ b/tests/ui/sort_by_key_reverse.fixed @@ -12,4 +12,11 @@ fn main() { vec.sort_by_key(|&b| Reverse(b)); vec.sort_by_key(|&b| Reverse((b + 5).abs())); vec.sort_by_key(|&b| Reverse(id(-b))); + // Negative examples (shouldn't be changed) + let c = &7; + vec.sort_by(|a, b| (b - a).cmp(&(a - b))); + vec.sort_by(|_, b| b.cmp(&5)); + vec.sort_by(|_, b| b.cmp(c)); + vec.sort_by(|a, _| a.cmp(c)); + vec.sort_by(|a, b| a.cmp(b)); } diff --git a/tests/ui/sort_by_key_reverse.rs b/tests/ui/sort_by_key_reverse.rs index 9c42d401755ad..601621ffa9f86 100644 --- a/tests/ui/sort_by_key_reverse.rs +++ b/tests/ui/sort_by_key_reverse.rs @@ -10,6 +10,13 @@ fn id(x: isize) -> isize { fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; vec.sort_by(|a, b| b.cmp(a)); - vec.sort_by(|a, b| (b + 5).abs().cmp(&(a+5).abs())); + vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); vec.sort_by(|a, b| id(-b).cmp(&id(-a))); + // Negative examples (shouldn't be changed) + let c = &7; + vec.sort_by(|a, b| (b - a).cmp(&(a - b))); + vec.sort_by(|_, b| b.cmp(&5)); + vec.sort_by(|_, b| b.cmp(c)); + vec.sort_by(|a, _| a.cmp(c)); + vec.sort_by(|a, b| a.cmp(b)); } diff --git a/tests/ui/sort_by_key_reverse.stderr b/tests/ui/sort_by_key_reverse.stderr index 3d26ddae78ad8..b757c8a6176d1 100644 --- a/tests/ui/sort_by_key_reverse.stderr +++ b/tests/ui/sort_by_key_reverse.stderr @@ -9,8 +9,8 @@ LL | vec.sort_by(|a, b| b.cmp(a)); error: use Vec::sort_by_key here instead --> $DIR/sort_by_key_reverse.rs:13:5 | -LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a+5).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` +LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` error: use Vec::sort_by_key here instead --> $DIR/sort_by_key_reverse.rs:14:5 From 059e8edd15401d5544260e4058731dc8818578d5 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Sun, 24 May 2020 19:45:41 -0700 Subject: [PATCH 524/695] Detect also a non-reversed comparison --- clippy_lints/src/lib.rs | 10 ++-- ...{sort_by_key_reverse.rs => sort_by_key.rs} | 52 +++++++++++-------- ...by_key_reverse.fixed => sort_by_key.fixed} | 8 ++- ...{sort_by_key_reverse.rs => sort_by_key.rs} | 6 ++- tests/ui/sort_by_key.stderr | 48 +++++++++++++++++ tests/ui/sort_by_key_reverse.stderr | 22 -------- 6 files changed, 94 insertions(+), 52 deletions(-) rename clippy_lints/src/{sort_by_key_reverse.rs => sort_by_key.rs} (83%) rename tests/ui/{sort_by_key_reverse.fixed => sort_by_key.fixed} (72%) rename tests/ui/{sort_by_key_reverse.rs => sort_by_key.rs} (78%) create mode 100644 tests/ui/sort_by_key.stderr delete mode 100644 tests/ui/sort_by_key_reverse.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e7a4c1ecaa954..9e826316f2186 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -304,7 +304,7 @@ mod serde_api; mod shadow; mod single_component_path_imports; mod slow_vector_initialization; -mod sort_by_key_reverse; +mod sort_by_key; mod strings; mod suspicious_trait_impl; mod swap; @@ -780,7 +780,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_UNRELATED, &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - &sort_by_key_reverse::SORT_BY_KEY_REVERSE, + &sort_by_key::SORT_BY_KEY, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, &strings::STRING_LIT_AS_BYTES, @@ -998,7 +998,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast); store.register_late_pass(|| box redundant_clone::RedundantClone); store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); - store.register_late_pass(|| box sort_by_key_reverse::SortByKeyReverse); + store.register_late_pass(|| box sort_by_key::SortByKey); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); @@ -1394,7 +1394,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(&sort_by_key_reverse::SORT_BY_KEY_REVERSE), + LintId::of(&sort_by_key::SORT_BY_KEY), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), @@ -1596,7 +1596,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), - LintId::of(&sort_by_key_reverse::SORT_BY_KEY_REVERSE), + LintId::of(&sort_by_key::SORT_BY_KEY), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), diff --git a/clippy_lints/src/sort_by_key_reverse.rs b/clippy_lints/src/sort_by_key.rs similarity index 83% rename from clippy_lints/src/sort_by_key_reverse.rs rename to clippy_lints/src/sort_by_key.rs index ea850955db121..109845a28f446 100644 --- a/clippy_lints/src/sort_by_key_reverse.rs +++ b/clippy_lints/src/sort_by_key.rs @@ -11,33 +11,35 @@ use rustc_span::symbol::Ident; declare_clippy_lint! { /// **What it does:** /// Detects when people use `Vec::sort_by` and pass in a function - /// which compares the second argument to the first. + /// which compares the two arguments, either directly or indirectly. /// /// **Why is this bad?** - /// It is more clear to use `Vec::sort_by_key` and `std::cmp::Reverse` + /// It is more clear to use `Vec::sort_by_key` (or + /// `Vec::sort_by_key` and `std::cmp::Reverse` if necessary) than + /// using /// /// **Known problems:** None. /// /// **Example:** /// /// ```rust - /// vec.sort_by(|a, b| b.foo().cmp(&a.foo())); + /// vec.sort_by(|a, b| a.foo().cmp(b.foo())); /// ``` /// Use instead: /// ```rust - /// vec.sort_by_key(|e| Reverse(e.foo())); + /// vec.sort_by_key(|a| a.foo()); /// ``` - pub SORT_BY_KEY_REVERSE, + pub SORT_BY_KEY, complexity, "Use of `Vec::sort_by` when `Vec::sort_by_key` would be clearer" } -declare_lint_pass!(SortByKeyReverse => [SORT_BY_KEY_REVERSE]); +declare_lint_pass!(SortByKey => [SORT_BY_KEY]); struct LintTrigger { vec_name: String, closure_arg: String, - closure_reverse_body: String, + closure_body: String, unstable: bool, } @@ -154,43 +156,49 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option if utils::match_type(cx, &cx.tables.expr_ty(vec), &paths::VEC); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ - Param { pat: Pat { kind: PatKind::Binding(_, _, a_ident, _), .. }, ..}, - Param { pat: Pat { kind: PatKind::Binding(_, _, b_ident, _), .. }, .. } + Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, + Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } ] = &closure_body.params; - if let ExprKind::MethodCall(method_path, _, [ref b_expr, ref a_expr]) = &closure_body.value.kind; + if let ExprKind::MethodCall(method_path, _, [ref left_expr, ref right_expr]) = &closure_body.value.kind; if method_path.ident.name.to_ident_string() == "cmp"; - if mirrored_exprs(&cx, &a_expr, &a_ident, &b_expr, &b_ident); then { + let (closure_body, closure_arg) = if mirrored_exprs( + &cx, + &left_expr, + &left_ident, + &right_expr, + &right_ident + ) { + (Sugg::hir(cx, &left_expr, "..").to_string(), left_ident.name.to_string()) + } else if mirrored_exprs(&cx, &left_expr, &right_ident, &right_expr, &left_ident) { + (format!("Reverse({})", Sugg::hir(cx, &left_expr, "..").to_string()), right_ident.name.to_string()) + } else { + return None; + }; let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); let unstable = name == "sort_unstable_by"; - let closure_arg = format!("&{}", b_ident.name.to_ident_string()); - let closure_reverse_body = Sugg::hir(cx, &b_expr, "..").to_string(); - // Get rid of parentheses, because they aren't needed anymore - // while closure_reverse_body.chars().next() == Some('(') && closure_reverse_body.chars().last() == Some(')') { - // closure_reverse_body = String::from(&closure_reverse_body[1..closure_reverse_body.len()-1]); - // } - Some(LintTrigger { vec_name, unstable, closure_arg, closure_reverse_body }) + Some(LintTrigger { vec_name, unstable, closure_arg, closure_body }) } else { None } } } -impl LateLintPass<'_, '_> for SortByKeyReverse { +impl LateLintPass<'_, '_> for SortByKey { fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { if let Some(trigger) = detect_lint(cx, expr) { utils::span_lint_and_sugg( cx, - SORT_BY_KEY_REVERSE, + SORT_BY_KEY, expr.span, "use Vec::sort_by_key here instead", "try", format!( - "{}.sort{}_by_key(|{}| Reverse({}))", + "{}.sort{}_by_key(|&{}| {})", trigger.vec_name, if trigger.unstable { "_unstable" } else { "" }, trigger.closure_arg, - trigger.closure_reverse_body, + trigger.closure_body, ), Applicability::MachineApplicable, ); diff --git a/tests/ui/sort_by_key_reverse.fixed b/tests/ui/sort_by_key.fixed similarity index 72% rename from tests/ui/sort_by_key_reverse.fixed rename to tests/ui/sort_by_key.fixed index 722675a6b71a8..f6535c8d8f5dd 100644 --- a/tests/ui/sort_by_key_reverse.fixed +++ b/tests/ui/sort_by_key.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::sort_by_key_reverse)] +#![warn(clippy::sort_by_key)] use std::cmp::Reverse; @@ -9,6 +9,11 @@ fn id(x: isize) -> isize { fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; + // Forward examples + vec.sort_by_key(|&a| a); + vec.sort_by_key(|&a| (a + 5).abs()); + vec.sort_by_key(|&a| id(-a)); + // Reverse examples vec.sort_by_key(|&b| Reverse(b)); vec.sort_by_key(|&b| Reverse((b + 5).abs())); vec.sort_by_key(|&b| Reverse(id(-b))); @@ -18,5 +23,4 @@ fn main() { vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); vec.sort_by(|a, _| a.cmp(c)); - vec.sort_by(|a, b| a.cmp(b)); } diff --git a/tests/ui/sort_by_key_reverse.rs b/tests/ui/sort_by_key.rs similarity index 78% rename from tests/ui/sort_by_key_reverse.rs rename to tests/ui/sort_by_key.rs index 601621ffa9f86..953c573d406d8 100644 --- a/tests/ui/sort_by_key_reverse.rs +++ b/tests/ui/sort_by_key.rs @@ -9,6 +9,11 @@ fn id(x: isize) -> isize { fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; + // Forward examples + vec.sort_by(|a, b| a.cmp(b)); + vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); + vec.sort_by(|a, b| id(-a).cmp(&id(-b))); + // Reverse examples vec.sort_by(|a, b| b.cmp(a)); vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); vec.sort_by(|a, b| id(-b).cmp(&id(-a))); @@ -18,5 +23,4 @@ fn main() { vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); vec.sort_by(|a, _| a.cmp(c)); - vec.sort_by(|a, b| a.cmp(b)); } diff --git a/tests/ui/sort_by_key.stderr b/tests/ui/sort_by_key.stderr new file mode 100644 index 0000000000000..fa6a9a0fb10e7 --- /dev/null +++ b/tests/ui/sort_by_key.stderr @@ -0,0 +1,48 @@ +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key.rs:13:5 + | +LL | vec.sort_by(|a, b| a.cmp(b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| a)` + | + = note: `-D clippy::sort-by-key` implied by `-D warnings` + +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key.rs:14:5 + | +LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())` + +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key.rs:15:5 + | +LL | vec.sort_by(|a, b| id(-a).cmp(&id(-b))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| id(-a))` + +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key.rs:17:5 + | +LL | vec.sort_by(|a, b| b.cmp(a)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))` + +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key.rs:18:5 + | +LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` + +error: use Vec::sort_by_key here instead + --> $DIR/sort_by_key.rs:19:5 + | +LL | vec.sort_by(|a, b| id(-b).cmp(&id(-a))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(id(-b)))` + +error: unknown clippy lint: clippy::sort_by_key_reverse + --> $DIR/sort_by_key.rs:2:9 + | +LL | #![warn(clippy::sort_by_key_reverse)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::sort_by_key` + | + = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings` + +error: aborting due to 7 previous errors + diff --git a/tests/ui/sort_by_key_reverse.stderr b/tests/ui/sort_by_key_reverse.stderr deleted file mode 100644 index b757c8a6176d1..0000000000000 --- a/tests/ui/sort_by_key_reverse.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key_reverse.rs:12:5 - | -LL | vec.sort_by(|a, b| b.cmp(a)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))` - | - = note: `-D clippy::sort-by-key-reverse` implied by `-D warnings` - -error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key_reverse.rs:13:5 - | -LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` - -error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key_reverse.rs:14:5 - | -LL | vec.sort_by(|a, b| id(-b).cmp(&id(-a))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(id(-b)))` - -error: aborting due to 3 previous errors - From 07886a97640b89f72b70805f519bd9d42d7d1c4e Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Sun, 24 May 2020 20:05:58 -0700 Subject: [PATCH 525/695] Detect also when works --- clippy_lints/src/sort_by_key.rs | 49 ++++++++++++++++++++++++++++----- tests/ui/sort_by_key.fixed | 2 +- tests/ui/sort_by_key.stderr | 4 +-- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/sort_by_key.rs b/clippy_lints/src/sort_by_key.rs index 109845a28f446..f720d14473aff 100644 --- a/clippy_lints/src/sort_by_key.rs +++ b/clippy_lints/src/sort_by_key.rs @@ -3,7 +3,7 @@ use crate::utils::paths; use crate::utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, QPath}; +use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; @@ -16,7 +16,7 @@ declare_clippy_lint! { /// **Why is this bad?** /// It is more clear to use `Vec::sort_by_key` (or /// `Vec::sort_by_key` and `std::cmp::Reverse` if necessary) than - /// using + /// using /// /// **Known problems:** None. /// @@ -36,7 +36,17 @@ declare_clippy_lint! { declare_lint_pass!(SortByKey => [SORT_BY_KEY]); -struct LintTrigger { +enum LintTrigger { + Sort(SortDetection), + SortByKey(SortByKeyDetection), +} + +struct SortDetection { + vec_name: String, + unstable: bool, +} + +struct SortByKeyDetection { vec_name: String, closure_arg: String, closure_body: String, @@ -177,7 +187,18 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option }; let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); let unstable = name == "sort_unstable_by"; - Some(LintTrigger { vec_name, unstable, closure_arg, closure_body }) + if_chain! { + if let ExprKind::Path(QPath::Resolved(_, Path { + segments: [PathSegment { ident: left_name, .. }], .. + })) = &left_expr.kind; + if left_name == left_ident; + then { + Some(LintTrigger::Sort(SortDetection { vec_name, unstable })) + } + else { + Some(LintTrigger::SortByKey(SortByKeyDetection { vec_name, unstable, closure_arg, closure_body })) + } + } } else { None } @@ -186,8 +207,8 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option impl LateLintPass<'_, '_> for SortByKey { fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { - if let Some(trigger) = detect_lint(cx, expr) { - utils::span_lint_and_sugg( + match detect_lint(cx, expr) { + Some(LintTrigger::SortByKey(trigger)) => utils::span_lint_and_sugg( cx, SORT_BY_KEY, expr.span, @@ -201,7 +222,21 @@ impl LateLintPass<'_, '_> for SortByKey { trigger.closure_body, ), Applicability::MachineApplicable, - ); + ), + Some(LintTrigger::Sort(trigger)) => utils::span_lint_and_sugg( + cx, + SORT_BY_KEY, + expr.span, + "use Vec::sort here instead", + "try", + format!( + "{}.sort{}()", + trigger.vec_name, + if trigger.unstable { "_unstable" } else { "" }, + ), + Applicability::MachineApplicable, + ), + None => {}, } } } diff --git a/tests/ui/sort_by_key.fixed b/tests/ui/sort_by_key.fixed index f6535c8d8f5dd..bb88df1a56c92 100644 --- a/tests/ui/sort_by_key.fixed +++ b/tests/ui/sort_by_key.fixed @@ -10,7 +10,7 @@ fn id(x: isize) -> isize { fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples - vec.sort_by_key(|&a| a); + vec.sort(); vec.sort_by_key(|&a| (a + 5).abs()); vec.sort_by_key(|&a| id(-a)); // Reverse examples diff --git a/tests/ui/sort_by_key.stderr b/tests/ui/sort_by_key.stderr index fa6a9a0fb10e7..291fd5500f790 100644 --- a/tests/ui/sort_by_key.stderr +++ b/tests/ui/sort_by_key.stderr @@ -1,8 +1,8 @@ -error: use Vec::sort_by_key here instead +error: use Vec::sort here instead --> $DIR/sort_by_key.rs:13:5 | LL | vec.sort_by(|a, b| a.cmp(b)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| a)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()` | = note: `-D clippy::sort-by-key` implied by `-D warnings` From 015ab9f9259d58a48c171276f6e7190528f1a9ad Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Thu, 28 May 2020 18:18:25 -0700 Subject: [PATCH 526/695] Renamed to --- clippy_lints/src/lib.rs | 10 +++++----- .../{sort_by_key.rs => unnecessary_sort_by.rs} | 18 +++++++++--------- ..._by_key.fixed => unnecessary_sort_by.fixed} | 0 .../{sort_by_key.rs => unnecessary_sort_by.rs} | 0 ...y_key.stderr => unnecessary_sort_by.stderr} | 0 5 files changed, 14 insertions(+), 14 deletions(-) rename clippy_lints/src/{sort_by_key.rs => unnecessary_sort_by.rs} (95%) rename tests/ui/{sort_by_key.fixed => unnecessary_sort_by.fixed} (100%) rename tests/ui/{sort_by_key.rs => unnecessary_sort_by.rs} (100%) rename tests/ui/{sort_by_key.stderr => unnecessary_sort_by.stderr} (100%) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9e826316f2186..46df743b5bfd2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -304,7 +304,7 @@ mod serde_api; mod shadow; mod single_component_path_imports; mod slow_vector_initialization; -mod sort_by_key; +mod unnecessary_sort_by; mod strings; mod suspicious_trait_impl; mod swap; @@ -780,7 +780,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_UNRELATED, &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - &sort_by_key::SORT_BY_KEY, + &unnecessary_sort_by::UNNECESSARY_SORT_BY, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, &strings::STRING_LIT_AS_BYTES, @@ -998,7 +998,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast); store.register_late_pass(|| box redundant_clone::RedundantClone); store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); - store.register_late_pass(|| box sort_by_key::SortByKey); + store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); @@ -1394,7 +1394,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(&sort_by_key::SORT_BY_KEY), + LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), @@ -1596,7 +1596,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), - LintId::of(&sort_by_key::SORT_BY_KEY), + LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), diff --git a/clippy_lints/src/sort_by_key.rs b/clippy_lints/src/unnecessary_sort_by.rs similarity index 95% rename from clippy_lints/src/sort_by_key.rs rename to clippy_lints/src/unnecessary_sort_by.rs index f720d14473aff..c0858ec4c8880 100644 --- a/clippy_lints/src/sort_by_key.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -14,9 +14,9 @@ declare_clippy_lint! { /// which compares the two arguments, either directly or indirectly. /// /// **Why is this bad?** - /// It is more clear to use `Vec::sort_by_key` (or - /// `Vec::sort_by_key` and `std::cmp::Reverse` if necessary) than - /// using + /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if + /// possible) than to use `Vec::sort_by` and and a more complicated + /// closure. /// /// **Known problems:** None. /// @@ -29,12 +29,12 @@ declare_clippy_lint! { /// ```rust /// vec.sort_by_key(|a| a.foo()); /// ``` - pub SORT_BY_KEY, + pub UNNECESSARY_SORT_BY, complexity, - "Use of `Vec::sort_by` when `Vec::sort_by_key` would be clearer" + "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" } -declare_lint_pass!(SortByKey => [SORT_BY_KEY]); +declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]); enum LintTrigger { Sort(SortDetection), @@ -205,12 +205,12 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option } } -impl LateLintPass<'_, '_> for SortByKey { +impl LateLintPass<'_, '_> for UnnecessarySortBy { fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) { match detect_lint(cx, expr) { Some(LintTrigger::SortByKey(trigger)) => utils::span_lint_and_sugg( cx, - SORT_BY_KEY, + UNNECESSARY_SORT_BY, expr.span, "use Vec::sort_by_key here instead", "try", @@ -225,7 +225,7 @@ impl LateLintPass<'_, '_> for SortByKey { ), Some(LintTrigger::Sort(trigger)) => utils::span_lint_and_sugg( cx, - SORT_BY_KEY, + UNNECESSARY_SORT_BY, expr.span, "use Vec::sort here instead", "try", diff --git a/tests/ui/sort_by_key.fixed b/tests/ui/unnecessary_sort_by.fixed similarity index 100% rename from tests/ui/sort_by_key.fixed rename to tests/ui/unnecessary_sort_by.fixed diff --git a/tests/ui/sort_by_key.rs b/tests/ui/unnecessary_sort_by.rs similarity index 100% rename from tests/ui/sort_by_key.rs rename to tests/ui/unnecessary_sort_by.rs diff --git a/tests/ui/sort_by_key.stderr b/tests/ui/unnecessary_sort_by.stderr similarity index 100% rename from tests/ui/sort_by_key.stderr rename to tests/ui/unnecessary_sort_by.stderr From 20cb512e81ad03a014b40c377a01fdebaea66963 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Sun, 31 May 2020 12:06:32 -0700 Subject: [PATCH 527/695] Updated test cases and formatted --- clippy_lints/src/lib.rs | 2 +- tests/ui/unnecessary_sort_by.fixed | 1 - tests/ui/unnecessary_sort_by.rs | 1 - tests/ui/unnecessary_sort_by.stderr | 24 ++++++++---------------- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 46df743b5bfd2..fd832d1157772 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -304,7 +304,6 @@ mod serde_api; mod shadow; mod single_component_path_imports; mod slow_vector_initialization; -mod unnecessary_sort_by; mod strings; mod suspicious_trait_impl; mod swap; @@ -319,6 +318,7 @@ mod try_err; mod types; mod unicode; mod unnamed_address; +mod unnecessary_sort_by; mod unsafe_removed_from_name; mod unused_io_amount; mod unused_self; diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index bb88df1a56c92..4521ae38d4956 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -1,5 +1,4 @@ // run-rustfix -#![warn(clippy::sort_by_key)] use std::cmp::Reverse; diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index 953c573d406d8..fdb5a82336956 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -1,5 +1,4 @@ // run-rustfix -#![warn(clippy::sort_by_key_reverse)] use std::cmp::Reverse; diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index 291fd5500f790..b6365c1709db7 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -1,48 +1,40 @@ error: use Vec::sort here instead - --> $DIR/sort_by_key.rs:13:5 + --> $DIR/unnecessary_sort_by.rs:12:5 | LL | vec.sort_by(|a, b| a.cmp(b)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()` | - = note: `-D clippy::sort-by-key` implied by `-D warnings` + = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key.rs:14:5 + --> $DIR/unnecessary_sort_by.rs:13:5 | LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())` error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key.rs:15:5 + --> $DIR/unnecessary_sort_by.rs:14:5 | LL | vec.sort_by(|a, b| id(-a).cmp(&id(-b))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| id(-a))` error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key.rs:17:5 + --> $DIR/unnecessary_sort_by.rs:16:5 | LL | vec.sort_by(|a, b| b.cmp(a)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))` error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key.rs:18:5 + --> $DIR/unnecessary_sort_by.rs:17:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` error: use Vec::sort_by_key here instead - --> $DIR/sort_by_key.rs:19:5 + --> $DIR/unnecessary_sort_by.rs:18:5 | LL | vec.sort_by(|a, b| id(-b).cmp(&id(-a))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(id(-b)))` -error: unknown clippy lint: clippy::sort_by_key_reverse - --> $DIR/sort_by_key.rs:2:9 - | -LL | #![warn(clippy::sort_by_key_reverse)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::sort_by_key` - | - = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings` - -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors From 8894bd220b82de486f2a8aecec6753c1b416b1f2 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 31 May 2020 16:11:51 +0100 Subject: [PATCH 528/695] Add descriptions for all queries --- src/librustc_macros/src/query.rs | 57 +++-- src/librustc_middle/query/mod.rs | 234 +++++++++++++----- src/librustc_query_system/query/config.rs | 23 -- ...9-assoc-const-static-recursion-impl.stderr | 2 +- ...onst-static-recursion-trait-default.stderr | 2 +- ...-assoc-const-static-recursion-trait.stderr | 2 +- src/test/ui/consts/const-size_of-cycle.stderr | 2 +- ...le-projection-based-on-where-clause.stderr | 2 +- .../cycle-trait-default-type-trait.stderr | 8 +- src/test/ui/impl-trait/auto-trait-leak.stderr | 42 ++-- .../infinite/infinite-tag-type-recursion.rs | 2 +- .../infinite-tag-type-recursion.stderr | 4 +- .../infinite-vec-type-recursion.stderr | 4 +- src/test/ui/issues/issue-21177.stderr | 2 +- src/test/ui/issues/issue-34373.stderr | 6 +- .../issue-26548-recursion-via-normalize.rs | 11 +- ...issue-26548-recursion-via-normalize.stderr | 4 +- src/test/ui/resolve/issue-23305.stderr | 4 +- .../ui/resolve/resolve-self-in-impl.stderr | 20 +- 19 files changed, 257 insertions(+), 174 deletions(-) diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index 5f5bae66cfc65..41a49a38a19cf 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -199,7 +199,7 @@ impl Parse for Group { struct QueryModifiers { /// The description of the query. - desc: Option<(Option, Punctuated)>, + desc: (Option, Punctuated), /// Use this type for the in-memory cache. storage: Option, @@ -295,6 +295,9 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { } } } + let desc = desc.unwrap_or_else(|| { + panic!("no description provided for query `{}`", query.name); + }); QueryModifiers { load_cached, storage, @@ -319,7 +322,7 @@ fn add_query_description_impl( let key = &query.key.0; // Find out if we should cache the query on disk - let cache = modifiers.cache.as_ref().map(|(args, expr)| { + let cache = if let Some((args, expr)) = modifiers.cache.as_ref() { let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() { // Use custom code to load the query from disk quote! { @@ -373,36 +376,32 @@ fn add_query_description_impl( #try_load_from_disk } - }); - - if cache.is_none() && modifiers.load_cached.is_some() { - panic!("load_cached modifier on query `{}` without a cache modifier", name); - } + } else { + if modifiers.load_cached.is_some() { + panic!("load_cached modifier on query `{}` without a cache modifier", name); + } + quote! {} + }; + + let (tcx, desc) = modifiers.desc; + let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ }); + + let desc = quote! { + #[allow(unused_variables)] + fn describe( + #tcx: TyCtxt<'tcx>, + #key: #arg, + ) -> Cow<'static, str> { + format!(#desc).into() + } + }; - let desc = modifiers.desc.as_ref().map(|(tcx, desc)| { - let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ }); - quote! { - #[allow(unused_variables)] - fn describe( - #tcx: TyCtxt<'tcx>, - #key: #arg, - ) -> Cow<'static, str> { - format!(#desc).into() - } + impls.extend(quote! { + impl<'tcx> QueryDescription> for queries::#name<'tcx> { + #desc + #cache } }); - - if desc.is_some() || cache.is_some() { - let cache = cache.unwrap_or(quote! {}); - let desc = desc.unwrap_or(quote! {}); - - impls.extend(quote! { - impl<'tcx> QueryDescription> for queries::#name<'tcx> { - #desc - #cache - } - }); - } } pub fn rustc_queries(input: TokenStream) -> TokenStream { diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 59b6f5e529baa..5a3ab205fc238 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -7,10 +7,10 @@ use crate::traits::query::{ CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; use crate::ty::query::queries; -use crate::ty::query::QueryDescription; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; +use rustc_query_system::query::QueryDescription; use rustc_span::symbol::Symbol; use std::borrow::Cow; @@ -91,6 +91,7 @@ rustc_queries! { /// Records the type of every item. query type_of(key: DefId) -> Ty<'tcx> { + desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } } @@ -102,6 +103,7 @@ rustc_queries! { /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its /// associated generics. query generics_of(key: DefId) -> ty::Generics { + desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { key.is_local() } load_cached(tcx, id) { @@ -127,6 +129,7 @@ rustc_queries! { /// to operate over only the actual where-clauses written by the /// user.) query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } } @@ -172,16 +175,17 @@ rustc_queries! { /// Fetch the MIR for a given `DefId` right after it's built - this includes /// unreachable code. - query mir_built(_: LocalDefId) -> Steal> { + query mir_built(key: LocalDefId) -> Steal> { storage(ArenaCacheSelector<'tcx>) - desc { "building MIR for" } + desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.to_def_id()) } } /// Fetch the MIR for a given `DefId` up till the point where it is - /// ready for const evaluation. + /// ready for const qualification. /// /// See the README for the `mir` module for details. - query mir_const(_: DefId) -> Steal> { + query mir_const(key: DefId) -> Steal> { + desc { |tcx| "processing MIR for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) no_hash } @@ -199,11 +203,13 @@ rustc_queries! { /// MIR after our optimization passes have run. This is MIR that is ready /// for codegen. This is also the only query that can fetch non-local MIR, at present. query optimized_mir(key: DefId) -> mir::Body<'tcx> { + desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { key.is_local() } } query promoted_mir(key: DefId) -> IndexVec> { + desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { key.is_local() } } @@ -237,14 +243,20 @@ rustc_queries! { /// predicates (where-clauses) directly defined on it. This is /// equal to the `explicit_predicates_of` predicates plus the /// `inferred_outlives_of` predicates. - query predicates_defined_on(_: DefId) -> ty::GenericPredicates<'tcx> {} + query predicates_defined_on(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) } + } /// Returns the predicates written explicitly by the user. - query explicit_predicates_of(_: DefId) -> ty::GenericPredicates<'tcx> {} + query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> { + desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } + } /// Returns the inferred outlives predicates (e.g., for `struct /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). - query inferred_outlives_of(_: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {} + query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] { + desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } + } /// Maps from the `DefId` of a trait to the list of /// super-predicates. This is a subset of the full list of @@ -265,12 +277,16 @@ rustc_queries! { }} } - query trait_def(_: DefId) -> ty::TraitDef { + query trait_def(key: DefId) -> ty::TraitDef { + desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) } - query adt_def(_: DefId) -> &'tcx ty::AdtDef { + query adt_def(key: DefId) -> &'tcx ty::AdtDef { + desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) } + } + query adt_destructor(key: DefId) -> Option { + desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) } } - query adt_destructor(_: DefId) -> Option {} // The cycle error here should be reported as an error by `check_representable`. // We consider the type as Sized in the meanwhile to avoid @@ -278,14 +294,17 @@ rustc_queries! { // Use `cycle_delay_bug` to delay the cycle error here to be emitted later // in case we accidentally otherwise don't emit an error. query adt_sized_constraint( - _: DefId + key: DefId ) -> AdtSizedConstraint<'tcx> { + desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) } cycle_delay_bug } query adt_dtorck_constraint( - _: DefId - ) -> Result, NoSolution> {} + key: DefId + ) -> Result, NoSolution> { + desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) } + } /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might @@ -316,18 +335,28 @@ rustc_queries! { /// be removed in the future in favour of some form of check which figures out whether the /// function does not inspect the bits of any of its arguments (so is essentially just a /// constructor function). - query is_promotable_const_fn(_: DefId) -> bool {} + query is_promotable_const_fn(key: DefId) -> bool { + desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) } + } - query const_fn_is_allowed_fn_ptr(_: DefId) -> bool {} + query const_fn_is_allowed_fn_ptr(key: DefId) -> bool { + desc { |tcx| "checking if const fn allows `fn()` types: `{}`", tcx.def_path_str(key) } + } /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). - query is_foreign_item(_: DefId) -> bool {} + query is_foreign_item(key: DefId) -> bool { + desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } + } /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item. - query static_mutability(_: DefId) -> Option {} + query static_mutability(def_id: DefId) -> Option { + desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) } + } /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. - query generator_kind(_: DefId) -> Option {} + query generator_kind(def_id: DefId) -> Option { + desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) } + } /// Gets a map with the variance of every item; use `item_variance` instead. query crate_variances(_: CrateNum) -> ty::CrateVariancesMap<'tcx> { @@ -336,7 +365,9 @@ rustc_queries! { } /// Maps from the `DefId` of a type or region parameter to its (inferred) variance. - query variances_of(_: DefId) -> &'tcx [ty::Variance] {} + query variances_of(def_id: DefId) -> &'tcx [ty::Variance] { + desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) } + } } TypeChecking { @@ -350,10 +381,13 @@ rustc_queries! { Other { /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items. - query associated_item_def_ids(_: DefId) -> &'tcx [DefId] {} + query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { + desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } + } /// Maps from a trait item to the trait item "descriptor". - query associated_item(_: DefId) -> ty::AssocItem { + query associated_item(key: DefId) -> ty::AssocItem { + desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) } @@ -363,17 +397,24 @@ rustc_queries! { desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } } - query impl_trait_ref(_: DefId) -> Option> {} - query impl_polarity(_: DefId) -> ty::ImplPolarity {} + query impl_trait_ref(key: DefId) -> Option> { + desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(key) } + } + query impl_polarity(key: DefId) -> ty::ImplPolarity { + desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(key) } + } - query issue33140_self_ty(_: DefId) -> Option> {} + query issue33140_self_ty(key: DefId) -> Option> { + desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) } + } } TypeChecking { /// Maps a `DefId` of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - query inherent_impls(_: DefId) -> &'tcx [DefId] { + query inherent_impls(key: DefId) -> &'tcx [DefId] { + desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) } eval_always } } @@ -395,8 +436,10 @@ rustc_queries! { desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } } - /// The signature of functions and closures. - query fn_sig(_: DefId) -> ty::PolyFnSig<'tcx> {} + /// The signature of functions. + query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> { + desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) } + } } Other { @@ -448,8 +491,10 @@ rustc_queries! { } /// Caches `CoerceUnsized` kinds for impls on custom types. - query coerce_unsized_info(_: DefId) - -> ty::adjustment::CoerceUnsizedInfo {} + query coerce_unsized_info(key: DefId) + -> ty::adjustment::CoerceUnsizedInfo { + desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } + } } TypeChecking { @@ -482,7 +527,9 @@ rustc_queries! { } TypeChecking { - query has_typeck_tables(_: DefId) -> bool {} + query has_typeck_tables(def_id: DefId) -> bool { + desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) } + } query coherent_trait(def_id: DefId) -> () { desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } @@ -579,6 +626,7 @@ rustc_queries! { TypeChecking { query check_match(key: DefId) { + desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } } @@ -600,7 +648,9 @@ rustc_queries! { /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; /// in the case of closures, this will be redirected to the enclosing function. - query region_scope_tree(_: DefId) -> &'tcx region::ScopeTree {} + query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree { + desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) } + } query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> { storage(ArenaCacheSelector<'tcx>) @@ -615,8 +665,11 @@ rustc_queries! { cache_on_disk_if { true } } - query def_kind(_: DefId) -> DefKind {} - query def_span(_: DefId) -> Span { + query def_kind(def_id: DefId) -> DefKind { + desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } + } + query def_span(def_id: DefId) -> Span { + desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) } // FIXME(mw): DefSpans are not really inputs since they are derived from // HIR. But at the moment HIR hashing still contains some hacks that allow // to make type debuginfo to be source location independent. Declaring @@ -624,29 +677,46 @@ rustc_queries! { // regardless of HIR hashing. eval_always } - query lookup_stability(_: DefId) -> Option<&'tcx attr::Stability> {} - query lookup_const_stability(_: DefId) -> Option<&'tcx attr::ConstStability> {} - query lookup_deprecation_entry(_: DefId) -> Option {} - query item_attrs(_: DefId) -> &'tcx [ast::Attribute] {} + query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> { + desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) } + } + query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> { + desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) } + } + query lookup_deprecation_entry(def_id: DefId) -> Option { + desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) } + } + query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] { + desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) } + } } Codegen { - query codegen_fn_attrs(_: DefId) -> CodegenFnAttrs { + query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs { + desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { true } } } Other { - query fn_arg_names(_: DefId) -> &'tcx [Symbol] {} + query fn_arg_names(def_id: DefId) -> &'tcx [Symbol] { + desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } + } /// Gets the rendered value of the specified constant or associated constant. /// Used by rustdoc. - query rendered_const(_: DefId) -> String {} - query impl_parent(_: DefId) -> Option {} + query rendered_const(def_id: DefId) -> String { + desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) } + } + query impl_parent(def_id: DefId) -> Option { + desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) } + } } TypeChecking { - query trait_of_item(_: DefId) -> Option {} + query trait_of_item(def_id: DefId) -> Option { + desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(def_id) } + } } Codegen { @@ -692,12 +762,14 @@ rustc_queries! { } /// Gets the ParameterEnvironment for a given item; this environment - /// will be in "user-facing" mode, meaning that it is suitabe for + /// will be in "user-facing" mode, meaning that it is suitable for /// type-checking etc, and it does not normalize specializable /// associated types. This is almost always what you want, /// unless you are doing MIR optimizations, in which case you /// might want to use `reveal_all()` method to change modes. - query param_env(_: DefId) -> ty::ParamEnv<'tcx> {} + query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> { + desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) } + } /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, /// `ty.is_copy()`, etc, since that will prune the environment where possible. @@ -720,7 +792,8 @@ rustc_queries! { /// A list of types where the ADT requires drop if and only if any of /// those types require drop. If the ADT is known to always need drop /// then `Err(AlwaysRequiresDrop)` is returned. - query adt_drop_tys(_: DefId) -> Result<&'tcx ty::List>, AlwaysRequiresDrop> { + query adt_drop_tys(def_id: DefId) -> Result<&'tcx ty::List>, AlwaysRequiresDrop> { + desc { |tcx| "computing when `{}` needs drop", tcx.def_path_str(def_id) } cache_on_disk_if { true } } @@ -774,7 +847,7 @@ rustc_queries! { desc { "query a crate's symbol mangling version" } } - query extern_crate(_: DefId) -> Option<&'tcx ExternCrate> { + query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> { eval_always desc { "getting crate's ExternCrateData" } } @@ -792,25 +865,29 @@ rustc_queries! { } Other { - query module_exports(_: DefId) -> Option<&'tcx [Export]> { + query module_exports(def_id: DefId) -> Option<&'tcx [Export]> { + desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id) } eval_always } } TypeChecking { - query impl_defaultness(_: DefId) -> hir::Defaultness {} + query impl_defaultness(def_id: DefId) -> hir::Defaultness { + desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } + } query check_item_well_formed(key: LocalDefId) -> () { - desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } + desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } } query check_trait_item_well_formed(key: LocalDefId) -> () { - desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } + desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } } query check_impl_item_well_formed(key: LocalDefId) -> () { - desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } + desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) } } } + Linking { // The `DefId`s of all non-generic functions and statics in the given crate // that can be reached from outside the crate. @@ -829,8 +906,15 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) desc { "looking up the exported symbols of a crate" } } - query is_reachable_non_generic(_: DefId) -> bool {} - query is_unreachable_local_definition(_: DefId) -> bool {} + query is_reachable_non_generic(def_id: DefId) -> bool { + desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) } + } + query is_unreachable_local_definition(def_id: DefId) -> bool { + desc { |tcx| + "checking whether `{}` is reachable from outside the crate", + tcx.def_path_str(def_id), + } + } } Codegen { @@ -854,8 +938,13 @@ rustc_queries! { /// /// You likely want to call `Instance::upstream_monomorphization()` /// instead of invoking this query directly. - query upstream_monomorphizations_for(_: DefId) - -> Option<&'tcx FxHashMap, CrateNum>> {} + query upstream_monomorphizations_for(def_id: DefId) + -> Option<&'tcx FxHashMap, CrateNum>> { + desc { |tcx| + "collecting available upstream monomorphizations for `{}`", + tcx.def_path_str(def_id), + } + } /// Returns the upstream crate that exports drop-glue for the given /// type (`substs` is expected to be a single-item list containing the @@ -932,10 +1021,16 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) desc { "dllimport_foreign_items" } } - query is_dllimport_foreign_item(_: DefId) -> bool {} - query is_statically_included_foreign_item(_: DefId) -> bool {} - query native_library_kind(_: DefId) - -> Option {} + query is_dllimport_foreign_item(def_id: DefId) -> bool { + desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) } + } + query is_statically_included_foreign_item(def_id: DefId) -> bool { + desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) } + } + query native_library_kind(def_id: DefId) + -> Option { + desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) } + } } Linking { @@ -966,7 +1061,9 @@ rustc_queries! { } TypeChecking { - query visibility(_: DefId) -> ty::Visibility {} + query visibility(def_id: DefId) -> ty::Visibility { + desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } + } } Other { @@ -978,9 +1075,11 @@ rustc_queries! { eval_always desc { "fetching what a crate is named" } } - query item_children(_: DefId) -> &'tcx [Export] {} - query extern_mod_stmt_cnum(_: LocalDefId) -> Option { - desc { "fetching extern module statement" } + query item_children(def_id: DefId) -> &'tcx [Export] { + desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) } + } + query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option { + desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) } } query get_lib_features(_: CrateNum) -> LibFeatures { @@ -1040,7 +1139,8 @@ rustc_queries! { desc { "generating a postorder list of CrateNums" } } - query upvars_mentioned(_: DefId) -> Option<&'tcx FxIndexMap> { + query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap> { + desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } eval_always } query maybe_unused_trait_import(def_id: LocalDefId) -> bool { @@ -1094,7 +1194,9 @@ rustc_queries! { eval_always desc { "collect_and_partition_mono_items" } } - query is_codegened_item(_: DefId) -> bool {} + query is_codegened_item(def_id: DefId) -> bool { + desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) } + } query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } diff --git a/src/librustc_query_system/query/config.rs b/src/librustc_query_system/query/config.rs index f031b54346fa9..549056570f9bc 100644 --- a/src/librustc_query_system/query/config.rs +++ b/src/librustc_query_system/query/config.rs @@ -6,7 +6,6 @@ use crate::query::caches::QueryCache; use crate::query::plumbing::CycleError; use crate::query::{QueryContext, QueryState}; use rustc_data_structures::profiling::ProfileCategory; -use rustc_span::def_id::DefId; use rustc_data_structures::fingerprint::Fingerprint; use std::borrow::Cow; @@ -132,25 +131,3 @@ where try_load_from_disk: Q::try_load_from_disk, }; } - -impl QueryDescription for M -where - M: QueryAccessors, -{ - default fn describe(tcx: CTX, def_id: DefId) -> Cow<'static, str> { - if !tcx.verbose() { - format!("processing `{}`", tcx.def_path_str(def_id)).into() - } else { - let name = ::std::any::type_name::(); - format!("processing {:?} with query `{}`", def_id, name).into() - } - } - - default fn cache_on_disk(_: CTX, _: &Self::Key, _: Option<&Self::Value>) -> bool { - false - } - - default fn try_load_from_disk(_: CTX, _: SerializedDepNodeIndex) -> Option { - panic!("QueryDescription::load_from_disk() called for an unsupported query.") - } -} diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index 01a34d310064c..1b4326ea56aaa 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -30,7 +30,7 @@ note: ...which requires const-evaluating `::BAR`... +note: ...which requires optimizing MIR for `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr index cad60cba1df62..8efa56a9a2e63 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr @@ -30,7 +30,7 @@ note: ...which requires const-evaluating `FooDefault::BAR`... | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `FooDefault::BAR`... +note: ...which requires optimizing MIR for `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index f415980dc1ea8..78ce1a28a3fdc 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -30,7 +30,7 @@ note: ...which requires const-evaluating `::BAR`... +note: ...which requires optimizing MIR for `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 730ad57de8169..5fd7fe4480e30 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -27,7 +27,7 @@ LL | pub fn size_of() -> usize; = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `[u8; _]`... = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle -note: cycle used when processing `Foo` +note: cycle used when checking that `Foo` is well-formed --> $DIR/const-size_of-cycle.rs:3:1 | LL | struct Foo { diff --git a/src/test/ui/cycle-projection-based-on-where-clause.stderr b/src/test/ui/cycle-projection-based-on-where-clause.stderr index 59815138e2e36..2c337cc6bf903 100644 --- a/src/test/ui/cycle-projection-based-on-where-clause.stderr +++ b/src/test/ui/cycle-projection-based-on-where-clause.stderr @@ -5,7 +5,7 @@ LL | T : Add | ^^^^^^^ | = note: ...which again requires computing the bounds for type parameter `T`, completing the cycle -note: cycle used when processing `A` +note: cycle used when computing explicit predicates of `A` --> $DIR/cycle-projection-based-on-where-clause.rs:17:19 | LL | T : Add diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr index 6b38d85302e66..58c458709a839 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr @@ -1,23 +1,23 @@ -error[E0391]: cycle detected when processing `Foo::X` +error[E0391]: cycle detected when computing type of `Foo::X` --> $DIR/cycle-trait-default-type-trait.rs:4:23 | LL | trait Foo> { | ^^^ | - = note: ...which again requires processing `Foo::X`, completing the cycle + = note: ...which again requires computing type of `Foo::X`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-default-type-trait.rs:4:1 | LL | trait Foo> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0391]: cycle detected when processing `Foo::X` +error[E0391]: cycle detected when computing type of `Foo::X` --> $DIR/cycle-trait-default-type-trait.rs:4:23 | LL | trait Foo> { | ^^^ | - = note: ...which again requires processing `Foo::X`, completing the cycle + = note: ...which again requires computing type of `Foo::X`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/cycle-trait-default-type-trait.rs:4:1 | diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 164524be1bc41..64d02f07048e2 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` +error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0` --> $DIR/auto-trait-leak.rs:12:16 | LL | fn cycle1() -> impl Clone { @@ -14,7 +14,7 @@ note: ...which requires processing `cycle1`... | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle1`... +note: ...which requires processing MIR for `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | LL | fn cycle1() -> impl Clone { @@ -24,7 +24,7 @@ note: ...which requires unsafety-checking `cycle1`... | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for... +note: ...which requires building MIR for `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | LL | fn cycle1() -> impl Clone { @@ -35,7 +35,7 @@ note: ...which requires type-checking `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle2::{{opaque}}#0`... +note: ...which requires computing type of `cycle2::{{opaque}}#0`... --> $DIR/auto-trait-leak.rs:22:16 | LL | fn cycle2() -> impl Clone { @@ -50,7 +50,7 @@ note: ...which requires processing `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle2`... +note: ...which requires processing MIR for `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { @@ -60,7 +60,7 @@ note: ...which requires unsafety-checking `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for... +note: ...which requires building MIR for `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { @@ -71,7 +71,7 @@ note: ...which requires type-checking `cycle2`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... - = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle + = note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 | @@ -84,7 +84,7 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` +error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0` --> $DIR/auto-trait-leak.rs:12:16 | LL | fn cycle1() -> impl Clone { @@ -100,7 +100,7 @@ note: ...which requires processing `cycle1`... | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle1`... +note: ...which requires processing MIR for `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | LL | fn cycle1() -> impl Clone { @@ -110,7 +110,7 @@ note: ...which requires unsafety-checking `cycle1`... | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for... +note: ...which requires building MIR for `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | LL | fn cycle1() -> impl Clone { @@ -121,7 +121,7 @@ note: ...which requires type-checking `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle2::{{opaque}}#0`... +note: ...which requires computing type of `cycle2::{{opaque}}#0`... --> $DIR/auto-trait-leak.rs:22:16 | LL | fn cycle2() -> impl Clone { @@ -136,7 +136,7 @@ note: ...which requires processing `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle2`... +note: ...which requires processing MIR for `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { @@ -146,7 +146,7 @@ note: ...which requires unsafety-checking `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for... +note: ...which requires building MIR for `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { @@ -156,7 +156,7 @@ note: ...which requires type-checking `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle + = note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 | @@ -169,7 +169,7 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` +error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0` --> $DIR/auto-trait-leak.rs:12:16 | LL | fn cycle1() -> impl Clone { @@ -185,7 +185,7 @@ note: ...which requires processing `cycle1`... | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle1`... +note: ...which requires processing MIR for `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | LL | fn cycle1() -> impl Clone { @@ -195,7 +195,7 @@ note: ...which requires unsafety-checking `cycle1`... | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for... +note: ...which requires building MIR for `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | LL | fn cycle1() -> impl Clone { @@ -206,7 +206,7 @@ note: ...which requires type-checking `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires processing `cycle2::{{opaque}}#0`... +note: ...which requires computing type of `cycle2::{{opaque}}#0`... --> $DIR/auto-trait-leak.rs:22:16 | LL | fn cycle2() -> impl Clone { @@ -221,7 +221,7 @@ note: ...which requires processing `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `cycle2`... +note: ...which requires processing MIR for `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { @@ -231,7 +231,7 @@ note: ...which requires unsafety-checking `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for... +note: ...which requires building MIR for `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | LL | fn cycle2() -> impl Clone { @@ -241,7 +241,7 @@ note: ...which requires type-checking `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle + = note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 | diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.rs b/src/test/ui/infinite/infinite-tag-type-recursion.rs index bbfaaa62f0d32..8578c5545bc90 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.rs +++ b/src/test/ui/infinite/infinite-tag-type-recursion.rs @@ -1,5 +1,5 @@ enum MList { Cons(isize, MList), Nil } //~^ ERROR recursive type `MList` has infinite size -//~| ERROR cycle detected when processing `MList` +//~| ERROR cycle detected when computing drop-check constraints for `MList` fn main() { let a = MList::Cons(10, MList::Cons(11, MList::Nil)); } diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 8f6529db0bec5..11f82b842ba6f 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -8,13 +8,13 @@ LL | enum MList { Cons(isize, MList), Nil } | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `MList` representable -error[E0391]: cycle detected when processing `MList` +error[E0391]: cycle detected when computing drop-check constraints for `MList` --> $DIR/infinite-tag-type-recursion.rs:1:1 | LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ | - = note: ...which again requires processing `MList`, completing the cycle + = note: ...which again requires computing drop-check constraints for `MList`, completing the cycle = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: MList } }` error: aborting due to 2 previous errors diff --git a/src/test/ui/infinite/infinite-vec-type-recursion.stderr b/src/test/ui/infinite/infinite-vec-type-recursion.stderr index be0db56f03449..77adefeb124e3 100644 --- a/src/test/ui/infinite/infinite-vec-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-vec-type-recursion.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when processing `X` +error[E0391]: cycle detected when computing type of `X` --> $DIR/infinite-vec-type-recursion.rs:1:14 | LL | type X = Vec; | ^ | - = note: ...which again requires processing `X`, completing the cycle + = note: ...which again requires computing type of `X`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/infinite-vec-type-recursion.rs:1:1 | diff --git a/src/test/ui/issues/issue-21177.stderr b/src/test/ui/issues/issue-21177.stderr index 00d9a3c46a723..59cc6550a8bd6 100644 --- a/src/test/ui/issues/issue-21177.stderr +++ b/src/test/ui/issues/issue-21177.stderr @@ -5,7 +5,7 @@ LL | fn foo>() { } | ^^^^ | = note: ...which again requires computing the bounds for type parameter `T`, completing the cycle -note: cycle used when processing `foo` +note: cycle used when computing explicit predicates of `foo` --> $DIR/issue-21177.rs:6:21 | LL | fn foo>() { } diff --git a/src/test/ui/issues/issue-34373.stderr b/src/test/ui/issues/issue-34373.stderr index f260a8477431b..e8c1e8f966973 100644 --- a/src/test/ui/issues/issue-34373.stderr +++ b/src/test/ui/issues/issue-34373.stderr @@ -1,15 +1,15 @@ -error[E0391]: cycle detected when processing `Foo::T` +error[E0391]: cycle detected when computing type of `Foo::T` --> $DIR/issue-34373.rs:7:30 | LL | pub struct Foo>>; | ^^^^^^^^^^ | -note: ...which requires processing `DefaultFoo`... +note: ...which requires computing type of `DefaultFoo`... --> $DIR/issue-34373.rs:8:19 | LL | type DefaultFoo = Foo; | ^^^ - = note: ...which again requires processing `Foo::T`, completing the cycle + = note: ...which again requires computing type of `Foo::T`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-34373.rs:1:1 | diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs b/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs index 6ee8c0fcfdade..4d1cd059c27b5 100644 --- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs +++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs @@ -4,10 +4,15 @@ // build-fail -trait Mirror { type It: ?Sized; } -impl Mirror for T { type It = Self; } +trait Mirror { + type It: ?Sized; +} +impl Mirror for T { + type It = Self; +} struct S(Option<::It>); -fn main() { //~ NOTE cycle used when processing `main` +fn main() { + //~^ NOTE cycle used when optimizing MIR for `main` let _s = S(None); } diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr index 6a83f91ce5b32..be55890c08c88 100644 --- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr +++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr @@ -2,8 +2,8 @@ error[E0391]: cycle detected when computing layout of `std::option::Option` | = note: ...which requires computing layout of `S`... = note: ...which again requires computing layout of `std::option::Option`, completing the cycle -note: cycle used when processing `main` - --> $DIR/issue-26548-recursion-via-normalize.rs:11:1 +note: cycle used when optimizing MIR for `main` + --> $DIR/issue-26548-recursion-via-normalize.rs:15:1 | LL | fn main() { | ^^^^^^^^^ diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr index 0ed3af81d5668..525b5cf7d8417 100644 --- a/src/test/ui/resolve/issue-23305.stderr +++ b/src/test/ui/resolve/issue-23305.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when processing `` +error[E0391]: cycle detected when computing type of `` --> $DIR/issue-23305.rs:5:16 | LL | impl dyn ToNbt {} | ^^^^ | - = note: ...which again requires processing ``, completing the cycle + = note: ...which again requires computing type of ``, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23305.rs:1:1 | diff --git a/src/test/ui/resolve/resolve-self-in-impl.stderr b/src/test/ui/resolve/resolve-self-in-impl.stderr index 58e851e5c12ca..5b5c1834cad19 100644 --- a/src/test/ui/resolve/resolve-self-in-impl.stderr +++ b/src/test/ui/resolve/resolve-self-in-impl.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when processing `` +error[E0391]: cycle detected when computing type of `` --> $DIR/resolve-self-in-impl.rs:14:13 | LL | impl Tr for Self {} | ^^^^ | - = note: ...which again requires processing ``, completing the cycle + = note: ...which again requires computing type of ``, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -17,13 +17,13 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when processing `` +error[E0391]: cycle detected when computing type of `` --> $DIR/resolve-self-in-impl.rs:15:15 | LL | impl Tr for S {} | ^^^^ | - = note: ...which again requires processing ``, completing the cycle + = note: ...which again requires computing type of ``, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -36,13 +36,13 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when processing `` +error[E0391]: cycle detected when computing type of `` --> $DIR/resolve-self-in-impl.rs:16:6 | LL | impl Self {} | ^^^^ | - = note: ...which again requires processing ``, completing the cycle + = note: ...which again requires computing type of ``, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -55,13 +55,13 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when processing `` +error[E0391]: cycle detected when computing type of `` --> $DIR/resolve-self-in-impl.rs:17:8 | LL | impl S {} | ^^^^ | - = note: ...which again requires processing ``, completing the cycle + = note: ...which again requires computing type of ``, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | @@ -74,13 +74,13 @@ LL | | LL | | fn main() {} | |____________^ -error[E0391]: cycle detected when processing `` +error[E0391]: cycle detected when computing trait implemented by `` --> $DIR/resolve-self-in-impl.rs:18:1 | LL | impl Tr for S {} | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: ...which again requires processing ``, completing the cycle + = note: ...which again requires computing trait implemented by ``, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/resolve-self-in-impl.rs:1:1 | From 32736606fd2317c4b19639ee3b4b8d18dcb8e83e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 31 May 2020 12:39:28 -0700 Subject: [PATCH 529/695] RELEASES.md: Expand `cargo tree` note to mention `cargo tree -d` Useful feature that people might not automatically associate with `cargo tree`. --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 7cba27e134a78..c8f51b7da4732 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -85,6 +85,8 @@ Cargo │ │ │ └── version_check v0.1.5 ... ``` + You can also display dependencies on multiple versions of the same crate with + `cargo tree -d` (short for `cargo tree --duplicates`). Misc ---- From 3048a41a5a042c2633a4d87ea38e04a1407f5bd3 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 31 May 2020 15:58:06 -0400 Subject: [PATCH 530/695] Rephrase term 'non-pointer type' If the reader assumes that 'pointer type's include 'smart pointer's, the term 'non-pointer type' could mislead the reader to assume that x should not be a smart pointer type. I tried to rephrase the term 'non-pointer type' to remove ambiguity in the doc comments. closes #72335 Thank you for reviewing this PR! :) --- src/libcore/ops/deref.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 6e96aa330ff19..3faeb170b0637 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -18,8 +18,8 @@ /// /// If `T` implements `Deref`, and `x` is a value of type `T`, then: /// -/// * In immutable contexts, `*x` on non-pointer types is equivalent to -/// `*Deref::deref(&x)`. +/// * In immutable contexts, `*x` (where `T` is neither a reference nor a raw pointer) +/// is equivalent to `*Deref::deref(&x)`. /// * Values of type `&T` are coerced to values of type `&U` /// * `T` implicitly implements all the (immutable) methods of the type `U`. /// @@ -115,8 +115,8 @@ impl Deref for &mut T { /// If `T` implements `DerefMut`, and `x` is a value of type `T`, /// then: /// -/// * In mutable contexts, `*x` on non-pointer types is equivalent to -/// `*DerefMut::deref_mut(&mut x)`. +/// * In mutable contexts, `*x` (where `T` is neither a reference nor a raw pointer) +/// is equivalent to `*DerefMut::deref_mut(&mut x)`. /// * Values of type `&mut T` are coerced to values of type `&mut U` /// * `T` implicitly implements all the (mutable) methods of the type `U`. /// From 32fde0b5116b3a1115d11c49a9bf2af2ebdd5773 Mon Sep 17 00:00:00 2001 From: Ericko Samudera Date: Mon, 25 May 2020 23:22:01 +0700 Subject: [PATCH 531/695] New lint: iter_next_slice --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + clippy_lints/src/loops.rs | 26 ++++----- clippy_lints/src/methods/mod.rs | 84 ++++++++++++++++++++++++++- clippy_lints/src/needless_continue.rs | 2 +- src/lintlist/mod.rs | 7 +++ tests/ui/into_iter_on_ref.fixed | 2 + tests/ui/into_iter_on_ref.rs | 2 + tests/ui/into_iter_on_ref.stderr | 8 ++- tests/ui/iter_next_slice.fixed | 24 ++++++++ tests/ui/iter_next_slice.rs | 24 ++++++++ tests/ui/iter_next_slice.stderr | 28 +++++++++ tests/ui/needless_collect.fixed | 2 +- tests/ui/needless_collect.stderr | 16 ++--- 14 files changed, 204 insertions(+), 25 deletions(-) create mode 100644 tests/ui/iter_next_slice.fixed create mode 100644 tests/ui/iter_next_slice.rs create mode 100644 tests/ui/iter_next_slice.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ac9057199ff3..714e25a32ea64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1401,6 +1401,7 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop +[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 057d39d4c8252..7c16dbd8f2676 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -669,6 +669,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::INTO_ITER_ON_REF, &methods::ITERATOR_STEP_BY_ZERO, &methods::ITER_CLONED_COLLECT, + &methods::ITER_NEXT_SLICE, &methods::ITER_NTH, &methods::ITER_NTH_ZERO, &methods::ITER_SKIP_NEXT, @@ -1303,6 +1304,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_NEXT_SLICE), LintId::of(&methods::ITER_NTH), LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), @@ -1483,6 +1485,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), + LintId::of(&methods::ITER_NEXT_SLICE), LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 38a5829b3f745..dbe41823a9cf6 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -27,7 +27,7 @@ use rustc_middle::middle::region; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::BytePos; +use rustc_span::symbol::Symbol; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; use std::iter::{once, Iterator}; use std::mem; @@ -2381,32 +2381,32 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' match_type(cx, ty, &paths::BTREEMAP) || is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { if method.ident.name == sym!(len) { - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(collect)); span_lint_and_sugg( cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, "replace with", - ".count()".to_string(), + "count()".to_string(), Applicability::MachineApplicable, ); } if method.ident.name == sym!(is_empty) { - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(iter)); span_lint_and_sugg( cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, "replace with", - ".next().is_none()".to_string(), + "get(0).is_none()".to_string(), Applicability::MachineApplicable, ); } if method.ident.name == sym!(contains) { let contains_arg = snippet(cx, args[1].span, "??"); - let span = shorten_needless_collect_span(expr); + let span = shorten_span(expr, sym!(collect)); span_lint_and_then( cx, NEEDLESS_COLLECT, @@ -2422,7 +2422,7 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' span, "replace with", format!( - ".any(|{}| x == {})", + "any(|{}| x == {})", arg, pred ), Applicability::MachineApplicable, @@ -2435,13 +2435,13 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, ' } } -fn shorten_needless_collect_span(expr: &Expr<'_>) -> Span { - if_chain! { - if let ExprKind::MethodCall(_, _, ref args) = expr.kind; - if let ExprKind::MethodCall(_, ref span, _) = args[0].kind; - then { - return expr.span.with_lo(span.lo() - BytePos(1)); +fn shorten_span(expr: &Expr<'_>, target_fn_name: Symbol) -> Span { + let mut current_expr = expr; + while let ExprKind::MethodCall(ref path, ref span, ref args) = current_expr.kind { + if path.ident.name == target_fn_name { + return expr.span.with_lo(span.lo()); } + current_expr = &args[0]; } unreachable!() } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 32b3b7f7947f6..7cb04d4d81c4c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -26,7 +26,7 @@ use rustc_span::symbol::{sym, SymbolStr}; use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; use crate::utils::{ - get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy, + get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy, is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, same_tys, single_segment_path, snippet, snippet_with_applicability, @@ -1242,6 +1242,32 @@ declare_clippy_lint! { "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array + /// + /// **Why is this bad?** These can be shortened into `.get()` + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// # let a = [1, 2, 3]; + /// # let b = vec![1, 2, 3]; + /// a[2..].iter().next(); + /// b.iter().next(); + /// ``` + /// should be written as: + /// ```rust + /// # let a = [1, 2, 3]; + /// # let b = vec![1, 2, 3]; + /// a.get(2); + /// b.get(0); + /// ``` + pub ITER_NEXT_SLICE, + style, + "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1273,6 +1299,7 @@ declare_lint_pass!(Methods => [ FIND_MAP, MAP_FLATTEN, ITERATOR_STEP_BY_ZERO, + ITER_NEXT_SLICE, ITER_NTH, ITER_NTH_ZERO, ITER_SKIP_NEXT, @@ -1320,6 +1347,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { }, ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]), ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]), + ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]), ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]), ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]), ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]), @@ -2184,6 +2212,60 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args } } +fn lint_iter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { + let caller_expr = &iter_args[0]; + + // Skip lint if the `iter().next()` expression is a for loop argument, + // since it is already covered by `&loops::ITER_NEXT_LOOP` + let mut parent_expr_opt = get_parent_expr(cx, expr); + while let Some(parent_expr) = parent_expr_opt { + if higher::for_loop(parent_expr).is_some() { + return; + } + parent_expr_opt = get_parent_expr(cx, parent_expr); + } + + if derefs_to_slice(cx, caller_expr, cx.tables.expr_ty(caller_expr)).is_some() { + // caller is a Slice + if_chain! { + if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind; + if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) + = higher::range(cx, index_expr); + if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind; + if let ast::LitKind::Int(start_idx, _) = start_lit.node; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "Using `.iter().next()` on a Slice without end index.", + "try calling", + format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx), + applicability, + ); + } + } + } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(caller_expr), sym!(vec_type)) + || matches!(&walk_ptrs_ty(cx.tables.expr_ty(caller_expr)).kind, ty::Array(_, _)) + { + // caller is a Vec or an Array + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NEXT_SLICE, + expr.span, + "Using `.iter().next()` on an array", + "try calling", + format!( + "{}.get(0)", + snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability) + ), + applicability, + ); + } +} + fn lint_iter_nth<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 28183810df489..a971d041ca661 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -424,7 +424,7 @@ fn erode_from_back(s: &str) -> String { } fn span_of_first_expr_in_block(block: &ast::Block) -> Option { - block.stmts.iter().next().map(|stmt| stmt.span) + block.stmts.get(0).map(|stmt| stmt.span) } #[cfg(test)] diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8211a57b56439..79da1f3702e35 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -934,6 +934,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "loops", }, + Lint { + name: "iter_next_slice", + group: "style", + desc: "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`", + deprecation: None, + module: "methods", + }, Lint { name: "iter_nth", group: "perf", diff --git a/tests/ui/into_iter_on_ref.fixed b/tests/ui/into_iter_on_ref.fixed index c30d23de3f869..7f92d0dbdc973 100644 --- a/tests/ui/into_iter_on_ref.fixed +++ b/tests/ui/into_iter_on_ref.fixed @@ -40,4 +40,6 @@ fn main() { let _ = (&HashSet::::new()).iter(); //~ WARN equivalent to .iter() let _ = std::path::Path::new("12/34").iter(); //~ WARN equivalent to .iter() let _ = std::path::PathBuf::from("12/34").iter(); //~ ERROR equivalent to .iter() + + let _ = (&[1, 2, 3]).iter().next(); //~ WARN equivalent to .iter() } diff --git a/tests/ui/into_iter_on_ref.rs b/tests/ui/into_iter_on_ref.rs index 94bc1689619a2..416056d3fdb9c 100644 --- a/tests/ui/into_iter_on_ref.rs +++ b/tests/ui/into_iter_on_ref.rs @@ -40,4 +40,6 @@ fn main() { let _ = (&HashSet::::new()).into_iter(); //~ WARN equivalent to .iter() let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() + + let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() } diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr index 80e2d104f824f..1cd6400b0195b 100644 --- a/tests/ui/into_iter_on_ref.stderr +++ b/tests/ui/into_iter_on_ref.stderr @@ -156,5 +156,11 @@ error: this `.into_iter()` call is equivalent to `.iter()` and will not move the LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: aborting due to 26 previous errors +error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array` + --> $DIR/into_iter_on_ref.rs:44:26 + | +LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() + | ^^^^^^^^^ help: call directly: `iter` + +error: aborting due to 27 previous errors diff --git a/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed new file mode 100644 index 0000000000000..79c1db87ac3c4 --- /dev/null +++ b/tests/ui/iter_next_slice.fixed @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::iter_next_slice)] + +fn main() { + // test code goes here + let s = [1, 2, 3]; + let v = vec![1, 2, 3]; + + s.get(0); + // Should be replaced by s.get(0) + + s.get(2); + // Should be replaced by s.get(2) + + v.get(5); + // Should be replaced by v.get(5) + + v.get(0); + // Should be replaced by v.get(0) + + let o = Some(5); + o.iter().next(); + // Shouldn't be linted since this is not a Slice or an Array +} diff --git a/tests/ui/iter_next_slice.rs b/tests/ui/iter_next_slice.rs new file mode 100644 index 0000000000000..ef9a55f3d997c --- /dev/null +++ b/tests/ui/iter_next_slice.rs @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::iter_next_slice)] + +fn main() { + // test code goes here + let s = [1, 2, 3]; + let v = vec![1, 2, 3]; + + s.iter().next(); + // Should be replaced by s.get(0) + + s[2..].iter().next(); + // Should be replaced by s.get(2) + + v[5..].iter().next(); + // Should be replaced by v.get(5) + + v.iter().next(); + // Should be replaced by v.get(0) + + let o = Some(5); + o.iter().next(); + // Shouldn't be linted since this is not a Slice or an Array +} diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr new file mode 100644 index 0000000000000..bbf61df0cda68 --- /dev/null +++ b/tests/ui/iter_next_slice.stderr @@ -0,0 +1,28 @@ +error: Using `.iter().next()` on an array + --> $DIR/iter_next_slice.rs:9:5 + | +LL | s.iter().next(); + | ^^^^^^^^^^^^^^^ help: try calling: `s.get(0)` + | + = note: `-D clippy::iter-next-slice` implied by `-D warnings` + +error: Using `.iter().next()` on a Slice without end index. + --> $DIR/iter_next_slice.rs:12:5 + | +LL | s[2..].iter().next(); + | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)` + +error: Using `.iter().next()` on a Slice without end index. + --> $DIR/iter_next_slice.rs:15:5 + | +LL | v[5..].iter().next(); + | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)` + +error: Using `.iter().next()` on an array + --> $DIR/iter_next_slice.rs:18:5 + | +LL | v.iter().next(); + | ^^^^^^^^^^^^^^^ help: try calling: `v.get(0)` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index b4227eaf2f8bb..be37dc16b9a3e 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -9,7 +9,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; fn main() { let sample = [1; 5]; let len = sample.iter().count(); - if sample.iter().next().is_none() { + if sample.get(0).is_none() { // Empty } sample.iter().cloned().any(|x| x == 1); diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr index 8884c8e161293..9113aad90dd7c 100644 --- a/tests/ui/needless_collect.stderr +++ b/tests/ui/needless_collect.stderr @@ -1,28 +1,28 @@ error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:11:28 + --> $DIR/needless_collect.rs:11:29 | LL | let len = sample.iter().collect::>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` | = note: `-D clippy::needless-collect` implied by `-D warnings` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:12:21 + --> $DIR/needless_collect.rs:12:15 | LL | if sample.iter().collect::>().is_empty() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.next().is_none()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get(0).is_none()` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:15:27 + --> $DIR/needless_collect.rs:15:28 | LL | sample.iter().cloned().collect::>().contains(&1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.any(|x| x == 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:16:34 + --> $DIR/needless_collect.rs:16:35 | LL | sample.iter().map(|x| (x, x)).collect::>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` error: aborting due to 4 previous errors From 7727c4ac7f3d4c977866bd8e6659a3e27f0bb6aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 28 May 2020 21:42:01 +0200 Subject: [PATCH 532/695] CONTRIBUTING: explain how to use cargo dev ra-setup Fixes #5514 --- CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0f47ac98fd20a..9f7bdcb1be7e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,14 +12,16 @@ anything, feel free to ask questions on issues or visit the `#clippy` on [Discor All contributors are expected to follow the [Rust Code of Conduct]. -* [Getting started](#getting-started) - * [Finding something to fix/improve](#finding-something-to-fiximprove) -* [Writing code](#writing-code) -* [How Clippy works](#how-clippy-works) -* [Fixing nightly build failures](#fixing-build-failures-caused-by-rust) -* [Issue and PR Triage](#issue-and-pr-triage) -* [Bors and Homu](#bors-and-homu) -* [Contributions](#contributions) +- [Contributing to Clippy](#contributing-to-clippy) + - [Getting started](#getting-started) + - [Finding something to fix/improve](#finding-something-to-fiximprove) + - [Writing code](#writing-code) + - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) + - [How Clippy works](#how-clippy-works) + - [Fixing build failures caused by Rust](#fixing-build-failures-caused-by-rust) + - [Issue and PR triage](#issue-and-pr-triage) + - [Bors and Homu](#bors-and-homu) + - [Contributions](#contributions) [Discord]: https://discord.gg/rust-lang [Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct @@ -91,6 +93,24 @@ quick read. [rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees [rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories +## Getting code-completion for rustc internals to work + +Unfortunately, [`rust-analyzer`][ra_homepage] does not (yet?) understand how Clippy uses compiler-internals +using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not +available via a `rustup` component at the time of writing. +To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via +`git clone https://github.com/rust-lang/rust/`. +Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies +which rust-analyzer will be able to understand. +Run `cargo dev ra-setup --repo-path ` where `` is an absolute path to the rustc repo +you just cloned. +The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to +Clippys `Cargo.toml`s and should allow rust-analyzer to understand most of the types that Clippy uses. +Just make sure to remove the dependencies again before finally making a pull request! + +[ra_homepage]: https://rust-analyzer.github.io/ +[rustc_repo]: https://github.com/rust-lang/rust/ + ## How Clippy works [`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers in the [`LintStore`]. From 717fd665ad1095b12907ed0f2426d8eb06c2bddc Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 26 May 2020 13:21:58 -0400 Subject: [PATCH 533/695] Make `SourceMap` available for early debug-printing of `Span`s Normally, we debug-print `Spans` using the `SourceMap` retrieved from the global `TyCtxt`. However, we fall back to printing out the `Span`'s raw fields (instead of a file and line number) when we try to print a `Span` before a `TyCtxt` is available. This makes debugging early phases of the compile, such as parsing, much more difficult. This commit stores a `SourceMap` in `rustc_span::GlOBALS` as a fallback. When a `TyCtxt` is not available, we try to retrieve one from `GLOBALS` - only if this is not available do we fall back to the raw field output. I'm not sure how to write a test for this - however, this can be verified locally by setting `RUSTC_LOG="rustc_parse=debug"`, and verifying that the output contains filenames and line numbers. --- src/librustc_interface/interface.rs | 24 ++++++++------- src/librustc_span/lib.rs | 45 +++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index f127a239eea2c..5aad64f84cee3 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -186,17 +186,19 @@ pub fn run_compiler_in_existing_thread_pool( override_queries: config.override_queries, }; - let r = { - let _sess_abort_error = OnDrop(|| { - compiler.sess.finish_diagnostics(registry); - }); - - f(&compiler) - }; - - let prof = compiler.sess.prof.clone(); - prof.generic_activity("drop_compiler").run(move || drop(compiler)); - r + rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { + let r = { + let _sess_abort_error = OnDrop(|| { + compiler.sess.finish_diagnostics(registry); + }); + + f(&compiler) + }; + + let prof = compiler.sess.prof.clone(); + prof.generic_activity("drop_compiler").run(move || drop(compiler)); + r + }) } pub fn run_compiler(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 616876d4b02a8..0f2eec48b4809 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -25,6 +25,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; mod caching_source_map_view; pub mod source_map; pub use self::caching_source_map_view::CachingSourceMapView; +use source_map::SourceMap; pub mod edition; use edition::Edition; @@ -67,6 +68,7 @@ pub struct Globals { symbol_interner: Lock, span_interner: Lock, hygiene_data: Lock, + source_map: Lock>>, } impl Globals { @@ -75,6 +77,7 @@ impl Globals { symbol_interner: Lock::new(symbol::Interner::fresh()), span_interner: Lock::new(span_encoding::SpanInterner::default()), hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), + source_map: Lock::new(None), } } } @@ -641,12 +644,44 @@ impl rustc_serialize::UseSpecializedDecodable for Span { } } +/// Calls the provided closure, using the provided `SourceMap` to format +/// any spans that are debug-printed during the closure'e exectuino. +/// +/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap` +/// (see `rustc_interface::callbacks::span_debug1). However, some parts +/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before +/// a `TyCtxt` is available. In this case, we fall back to +/// the `SourceMap` provided to this function. If that is not available, +/// we fall back to printing the raw `Span` field values +pub fn with_source_map T>(source_map: Lrc, f: F) -> T { + GLOBALS.with(|globals| { + *globals.source_map.borrow_mut() = Some(source_map); + }); + struct ClearSourceMap; + impl Drop for ClearSourceMap { + fn drop(&mut self) { + GLOBALS.with(|globals| { + globals.source_map.borrow_mut().take(); + }); + } + } + + let _guard = ClearSourceMap; + f() +} + pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Span") - .field("lo", &span.lo()) - .field("hi", &span.hi()) - .field("ctxt", &span.ctxt()) - .finish() + GLOBALS.with(|globals| { + if let Some(source_map) = &*globals.source_map.borrow() { + write!(f, "{}", source_map.span_to_string(span)) + } else { + f.debug_struct("Span") + .field("lo", &span.lo()) + .field("hi", &span.hi()) + .field("ctxt", &span.ctxt()) + .finish() + } + }) } impl fmt::Debug for Span { From 9a5baed482b68e0d9806e19eb9e8676d7ff3e1c2 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Sun, 31 May 2020 15:09:12 -0700 Subject: [PATCH 534/695] Implement suggestions from phansch --- clippy_lints/src/unnecessary_sort_by.rs | 41 ++++++++++++++++++++----- tests/ui/unnecessary_sort_by.fixed | 7 +++-- tests/ui/unnecessary_sort_by.rs | 7 +++-- tests/ui/unnecessary_sort_by.stderr | 26 ++++++++++------ 4 files changed, 57 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index c0858ec4c8880..33d8331c2923c 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -18,15 +18,25 @@ declare_clippy_lint! { /// possible) than to use `Vec::sort_by` and and a more complicated /// closure. /// - /// **Known problems:** None. + /// **Known problems:** + /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't + /// imported by a use statement in the current frame, then a `use` + /// statement that imports it will need to be added (which this lint + /// can't do). /// /// **Example:** /// /// ```rust - /// vec.sort_by(|a, b| a.foo().cmp(b.foo())); + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec = Vec::new(); + /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); /// ``` /// Use instead: /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec = Vec::new(); /// vec.sort_by_key(|a| a.foo()); /// ``` pub UNNECESSARY_SORT_BY, @@ -50,6 +60,7 @@ struct SortByKeyDetection { vec_name: String, closure_arg: String, closure_body: String, + reverse: bool, unstable: bool, } @@ -172,16 +183,16 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option if let ExprKind::MethodCall(method_path, _, [ref left_expr, ref right_expr]) = &closure_body.value.kind; if method_path.ident.name.to_ident_string() == "cmp"; then { - let (closure_body, closure_arg) = if mirrored_exprs( + let (closure_body, closure_arg, reverse) = if mirrored_exprs( &cx, &left_expr, &left_ident, &right_expr, &right_ident ) { - (Sugg::hir(cx, &left_expr, "..").to_string(), left_ident.name.to_string()) + (Sugg::hir(cx, &left_expr, "..").to_string(), left_ident.name.to_string(), false) } else if mirrored_exprs(&cx, &left_expr, &right_ident, &right_expr, &left_ident) { - (format!("Reverse({})", Sugg::hir(cx, &left_expr, "..").to_string()), right_ident.name.to_string()) + (Sugg::hir(cx, &left_expr, "..").to_string(), right_ident.name.to_string(), true) } else { return None; }; @@ -196,7 +207,13 @@ fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option Some(LintTrigger::Sort(SortDetection { vec_name, unstable })) } else { - Some(LintTrigger::SortByKey(SortByKeyDetection { vec_name, unstable, closure_arg, closure_body })) + Some(LintTrigger::SortByKey(SortByKeyDetection { + vec_name, + unstable, + closure_arg, + closure_body, + reverse + })) } } } else { @@ -219,9 +236,17 @@ impl LateLintPass<'_, '_> for UnnecessarySortBy { trigger.vec_name, if trigger.unstable { "_unstable" } else { "" }, trigger.closure_arg, - trigger.closure_body, + if trigger.reverse { + format!("Reverse({})", trigger.closure_body) + } else { + trigger.closure_body.to_string() + }, ), - Applicability::MachineApplicable, + if trigger.reverse { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, ), Some(LintTrigger::Sort(trigger)) => utils::span_lint_and_sugg( cx, diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 4521ae38d4956..779fd57707ad4 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -10,16 +10,17 @@ fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples vec.sort(); + vec.sort_unstable(); vec.sort_by_key(|&a| (a + 5).abs()); - vec.sort_by_key(|&a| id(-a)); + vec.sort_unstable_by_key(|&a| id(-a)); // Reverse examples vec.sort_by_key(|&b| Reverse(b)); vec.sort_by_key(|&b| Reverse((b + 5).abs())); - vec.sort_by_key(|&b| Reverse(id(-b))); + vec.sort_unstable_by_key(|&b| Reverse(id(-b))); // Negative examples (shouldn't be changed) let c = &7; vec.sort_by(|a, b| (b - a).cmp(&(a - b))); vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); - vec.sort_by(|a, _| a.cmp(c)); + vec.sort_unstable_by(|a, _| a.cmp(c)); } diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index fdb5a82336956..0485a5630afef 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -10,16 +10,17 @@ fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples vec.sort_by(|a, b| a.cmp(b)); + vec.sort_unstable_by(|a, b| a.cmp(b)); vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); - vec.sort_by(|a, b| id(-a).cmp(&id(-b))); + vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); // Reverse examples vec.sort_by(|a, b| b.cmp(a)); vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); - vec.sort_by(|a, b| id(-b).cmp(&id(-a))); + vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); // Negative examples (shouldn't be changed) let c = &7; vec.sort_by(|a, b| (b - a).cmp(&(a - b))); vec.sort_by(|_, b| b.cmp(&5)); vec.sort_by(|_, b| b.cmp(c)); - vec.sort_by(|a, _| a.cmp(c)); + vec.sort_unstable_by(|a, _| a.cmp(c)); } diff --git a/tests/ui/unnecessary_sort_by.stderr b/tests/ui/unnecessary_sort_by.stderr index b6365c1709db7..903b6e5099ce8 100644 --- a/tests/ui/unnecessary_sort_by.stderr +++ b/tests/ui/unnecessary_sort_by.stderr @@ -6,35 +6,41 @@ LL | vec.sort_by(|a, b| a.cmp(b)); | = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings` -error: use Vec::sort_by_key here instead +error: use Vec::sort here instead --> $DIR/unnecessary_sort_by.rs:13:5 | +LL | vec.sort_unstable_by(|a, b| a.cmp(b)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()` + +error: use Vec::sort_by_key here instead + --> $DIR/unnecessary_sort_by.rs:14:5 + | LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:14:5 + --> $DIR/unnecessary_sort_by.rs:15:5 | -LL | vec.sort_by(|a, b| id(-a).cmp(&id(-b))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| id(-a))` +LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&a| id(-a))` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:16:5 + --> $DIR/unnecessary_sort_by.rs:17:5 | LL | vec.sort_by(|a, b| b.cmp(a)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:17:5 + --> $DIR/unnecessary_sort_by.rs:18:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))` error: use Vec::sort_by_key here instead - --> $DIR/unnecessary_sort_by.rs:18:5 + --> $DIR/unnecessary_sort_by.rs:19:5 | -LL | vec.sort_by(|a, b| id(-b).cmp(&id(-a))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(id(-b)))` +LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&b| Reverse(id(-b)))` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors From b89880a30ce4dd7887614f305a565b6779dc4825 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Sun, 31 May 2020 15:19:31 -0700 Subject: [PATCH 535/695] Ran update_lints --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 6 +++--- src/lintlist/mod.rs | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c00f84bdb8570..086a1141be552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1555,7 +1555,6 @@ Released 2018-09-13 [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization -[`sort_by_key_reverse`]: https://rust-lang.github.io/rust-clippy/master/index.html#sort_by_key_reverse [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign @@ -1602,6 +1601,7 @@ Released 2018-09-13 [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation +[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fd832d1157772..03addf1f4a40c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -780,7 +780,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_UNRELATED, &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - &unnecessary_sort_by::UNNECESSARY_SORT_BY, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, &strings::STRING_LIT_AS_BYTES, @@ -835,6 +834,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unicode::ZERO_WIDTH_SPACE, &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, + &unnecessary_sort_by::UNNECESSARY_SORT_BY, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, @@ -1394,7 +1394,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), - LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), @@ -1431,6 +1430,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unicode::ZERO_WIDTH_SPACE), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), @@ -1596,7 +1596,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), - LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), @@ -1613,6 +1612,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNIT_ARG), LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), + LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b5d9ef0110e25..ab9542a7b9c8c 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1984,13 +1984,6 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "slow_vector_initialization", }, - Lint { - name: "sort_by_key_reverse", - group: "complexity", - desc: "Use of `Vec::sort_by` when `Vec::sort_by_key` would be clearer", - deprecation: None, - module: "sort_by_key_reverse", - }, Lint { name: "string_add", group: "restriction", @@ -2299,6 +2292,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "no_effect", }, + Lint { + name: "unnecessary_sort_by", + group: "complexity", + desc: "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer", + deprecation: None, + module: "unnecessary_sort_by", + }, Lint { name: "unnecessary_unwrap", group: "complexity", From 718d28cf85305411bdad8e3b2a4f932bd9f628c7 Mon Sep 17 00:00:00 2001 From: camelid Date: Sun, 31 May 2020 20:45:08 -0700 Subject: [PATCH 536/695] Correct generic parameter ordering in error note --- src/librustc_typeck/astconv.rs | 18 +++++++++++++++++- .../ui/suggestions/suggest-move-types.stderr | 4 ++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ab9db159038af..9b47c4c7dde70 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -8,6 +8,7 @@ use crate::collect::PlaceholderHirTyCollector; use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; +use rustc_ast::ast::ParamKindOrd; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::ErrorReported; @@ -483,8 +484,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg.descr(), kind, ); + + let kind_ord = match kind { + "lifetime" => ParamKindOrd::Lifetime, + "type" => ParamKindOrd::Type, + "constant" => ParamKindOrd::Const, + _ => panic!(), + }; + let arg_ord = match arg { + GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, + GenericArg::Type(_) => ParamKindOrd::Type, + GenericArg::Const(_) => ParamKindOrd::Const, + }; + // This note will be true as long as generic parameters are strictly ordered by their kind. - err.note(&format!("{} arguments must be provided before {} arguments", kind, arg.descr())); + let (first, last) = + if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) }; + err.note(&format!("{} arguments must be provided before {} arguments", first, last)); err.emit(); } diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 3bb6fd6e4f423..96f1656bae4ac 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -124,7 +124,7 @@ error[E0747]: lifetime provided when a type was expected LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { | ^^ | - = note: type arguments must be provided before lifetime arguments + = note: lifetime arguments must be provided before type arguments error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:82:56 @@ -132,7 +132,7 @@ error[E0747]: lifetime provided when a type was expected LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { | ^^ | - = note: type arguments must be provided before lifetime arguments + = note: lifetime arguments must be provided before type arguments error: aborting due to 12 previous errors From 6955420ace822ec888cc999a623c67c51ced839f Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 1 Jun 2020 00:28:58 +0200 Subject: [PATCH 537/695] Update changelog for stable:1.44 beta:1.45 --- CHANGELOG.md | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7dae3dcfff0f..fcc9895dd901d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,87 @@ document. ## Unreleased / In Rust Nightly -[891e1a8...master](https://github.com/rust-lang/rust-clippy/compare/891e1a8...master) +[7ea7cd1...master](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master) + +## Rust 1.45 + +Current beta, release 2020-07-16 + +[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1) + +### New lints + +* [`match_wildcard_for_single_variants`] [#5582](https://github.com/rust-lang/rust-clippy/pull/5582) +* [`unsafe_derive_deserialize`] [#5493](https://github.com/rust-lang/rust-clippy/pull/5493) +* [`if_let_mutex`] [#5332](https://github.com/rust-lang/rust-clippy/pull/5332) +* [`mismatched_target_os`] [#5506](https://github.com/rust-lang/rust-clippy/pull/5506) +* [`await_holding_lock`] [#5439](https://github.com/rust-lang/rust-clippy/pull/5439) +* [`match_on_vec_items`] [#5522](https://github.com/rust-lang/rust-clippy/pull/5522) +* [`manual_async_fn`] [#5576](https://github.com/rust-lang/rust-clippy/pull/5576) +* [`reversed_empty_ranges`] [#5583](https://github.com/rust-lang/rust-clippy/pull/5583) +* [`manual_non_exhaustive`] [#5550](https://github.com/rust-lang/rust-clippy/pull/5550) + +### Moves and Deprecations + +* Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408) +* Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622) +* Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599) +* Generalize [`option_and_then_some`] and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529) +* Rename [`identity_conversion`] to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568) +* Merge [`block_in_if_condition_expr`] and [`block_in_if_condition_stmt`] into [`blocks_in_if_conditions`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) +* Merge [`option_map_unwrap_or`], [`option_map_unwrap_or_else`] and [`result_map_unwrap_or_else`] into [`map_unwrap_or`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) +* Merge [`option_unwrap_used`] and [`result_unwrap_used`] into [`unwrap_used`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) +* Merge [`option_expect_used`] and [`result_expect_used`] into [`expect_used`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) +* Merge [`for_loop_over_option`] and [`for_loop_over_result`] into [`for_loops_over_fallibles`]. +[#5563](https://github.com/rust-lang/rust-clippy/pull/5563) + +### Enhancements + +* Avoid running cargo/internal lints when not enabled. [#5505](https://github.com/rust-lang/rust-clippy/pull/5505) +* Extend [`useless_conversion`] with `TryFrom` and `TryInto`. [#5631](https://github.com/rust-lang/rust-clippy/pull/5631) +* Lint also in type parameters and where clauses in [`unused_unit`]. [#5592](https://github.com/rust-lang/rust-clippy/pull/5592) +* Do not suggest deriving `Default` in [`new_without_default`]. [#5616](https://github.com/rust-lang/rust-clippy/pull/5616) + +### False Positive Fixes + +* [`while_let_on_iterator`] [#5525](https://github.com/rust-lang/rust-clippy/pull/5525) +* [`empty_line_after_outer_attr`] [#5609](https://github.com/rust-lang/rust-clippy/pull/5609) +* [`unnecessary_unwrap`] [#5558](https://github.com/rust-lang/rust-clippy/pull/5558) +* [`comparison_chain`] [#5596](https://github.com/rust-lang/rust-clippy/pull/5596) +* Don't trigger [`used_underscore_binding`] in await desugaring. [#5535](https://github.com/rust-lang/rust-clippy/pull/5535) +* Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491) +* Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602) +* Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564) +* Add ignores to the list of words of [`clippy::doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611) +* Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636) +* Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647) +* Honor lint level attributes for [`redundant_field_names`] and [`non_expressive_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651) +* Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429) + +### Suggestion Improvements + +* Simplify suggestions in [`manual_memcpy`]. [#5536](https://github.com/rust-lang/rust-clippy/pull/5536) +* Fix suggestion in [`redundant_pattern_matching`] for macros. [#5511](https://github.com/rust-lang/rust-clippy/pull/5511) +* Avoid suggesting `copied()` for mutable references in [`map_clone`]. [#5530](https://github.com/rust-lang/rust-clippy/pull/5530) +* Improve help message for [`clone_double_ref`]. [#5547](https://github.com/rust-lang/rust-clippy/pull/5547) + +### ICE Fixes + +* Fix ICE caused in unwrap module. [#5590](https://github.com/rust-lang/rust-clippy/pull/5590) +* Fix crash on rustc test issue-69020-assoc-const-arith-overflow.rs [#5499](https://github.com/rust-lang/rust-clippy/pull/5499) + +### Documentation + +* Clarify the documentation of [`unnecessary_mut_passed`]. [#5639](https://github.com/rust-lang/rust-clippy/pull/5639) +* Extend example for [`unneeded_field_pattern`]. [#5541](https://github.com/rust-lang/rust-clippy/pull/5541) ## Rust 1.44 -Current beta, release 2020-06-04 +Current stable, released 2020-06-04 [204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8) @@ -93,7 +169,7 @@ Current beta, release 2020-06-04 ## Rust 1.43 -Current stable, released 2020-04-23 +Released 2020-04-23 [4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b) From ae0ce2255aea7e896cbfc0330c9d4f17ed66b55f Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Mon, 1 Jun 2020 09:58:42 +0200 Subject: [PATCH 538/695] Add regression test for string_lit_as_bytes issue --- tests/ui/string_lit_as_bytes.fixed | 2 ++ tests/ui/string_lit_as_bytes.rs | 2 ++ tests/ui/string_lit_as_bytes.stderr | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index 7ad272ade5f9c..ccf8f61c4a92c 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -14,6 +14,8 @@ fn str_lit_as_bytes() { let strify = stringify!(foobar).as_bytes(); + let current_version = env!("CARGO_PKG_VERSION").as_bytes(); + let includestr = include_bytes!("entry_unfixable.rs"); let _ = b"string with newline\t\n"; diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index 1bf4538b7c94f..178df08e249ef 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -14,6 +14,8 @@ fn str_lit_as_bytes() { let strify = stringify!(foobar).as_bytes(); + let current_version = env!("CARGO_PKG_VERSION").as_bytes(); + let includestr = include_str!("entry_unfixable.rs").as_bytes(); let _ = "string with newline\t\n".as_bytes(); diff --git a/tests/ui/string_lit_as_bytes.stderr b/tests/ui/string_lit_as_bytes.stderr index ff6e3346dfc75..99c512354d589 100644 --- a/tests/ui/string_lit_as_bytes.stderr +++ b/tests/ui/string_lit_as_bytes.stderr @@ -13,13 +13,13 @@ LL | let bs = r###"raw string with 3# plus " ""###.as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###` error: calling `as_bytes()` on `include_str!(..)` - --> $DIR/string_lit_as_bytes.rs:17:22 + --> $DIR/string_lit_as_bytes.rs:19:22 | LL | let includestr = include_str!("entry_unfixable.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("entry_unfixable.rs")` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:19:13 + --> $DIR/string_lit_as_bytes.rs:21:13 | LL | let _ = "string with newline/t/n".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"` From 861b897c54200becd6767ad6e091abef61f15344 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Mon, 1 Jun 2020 10:20:17 +0200 Subject: [PATCH 539/695] Add regression test for endless loop This was fixed in pulldown_cmark 0.7.1, specifically https://github.com/raphlinus/pulldown-cmark/pull/438 --- clippy_lints/Cargo.toml | 2 +- tests/ui/crashes/regressions.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 98391732d1893..e959c1a651122 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -21,7 +21,7 @@ cargo_metadata = "0.9.1" if_chain = "1.0.0" itertools = "0.9" lazy_static = "1.0.2" -pulldown-cmark = { version = "0.7", default-features = false } +pulldown-cmark = { version = "0.7.1", default-features = false } quine-mc_cluskey = "0.2.2" regex-syntax = "0.6" serde = { version = "1.0", features = ["derive"] } diff --git a/tests/ui/crashes/regressions.rs b/tests/ui/crashes/regressions.rs index 623ae51f9f08c..3d5063d1a3a7d 100644 --- a/tests/ui/crashes/regressions.rs +++ b/tests/ui/crashes/regressions.rs @@ -6,4 +6,8 @@ pub fn foo(bar: *const u8) { println!("{:#p}", bar); } +// Regression test for https://github.com/rust-lang/rust-clippy/issues/4917 +/// Date: Wed, 27 May 2020 16:24:53 +0200 Subject: [PATCH 540/695] Fix some code examples in doc --- clippy_lints/src/assign_ops.rs | 4 +++ clippy_lints/src/double_parens.rs | 18 +++++++++++-- clippy_lints/src/drop_bounds.rs | 4 +++ clippy_lints/src/duration_subsec.rs | 6 +++++ clippy_lints/src/enum_variants.rs | 32 +++++++++++++++++++---- clippy_lints/src/eq_op.rs | 4 +++ clippy_lints/src/escape.rs | 7 +++++ clippy_lints/src/eta_reduction.rs | 4 +++ clippy_lints/src/eval_order_dependence.rs | 6 +++++ 9 files changed, 78 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index 05e2650d0b715..13e61fe98bac1 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -24,7 +24,11 @@ declare_clippy_lint! { /// let mut a = 5; /// let b = 0; /// // ... + /// // Bad /// a = a + b; + /// + /// // Good + /// a += b; /// ``` pub ASSIGN_OP_PATTERN, style, diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 7f2ff8b9b26f6..05517f6f9f0cc 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -13,10 +13,24 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad + /// fn simple_double_parens() -> i32 { + /// ((0)) + /// } + /// + /// // Good + /// fn simple_no_parens() -> i32 { + /// 0 + /// } + /// + /// // or + /// /// # fn foo(bar: usize) {} - /// ((0)); + /// // Bad /// foo((0)); - /// ((1, 2)); + /// + /// // Good + /// foo(0); /// ``` pub DOUBLE_PARENS, complexity, diff --git a/clippy_lints/src/drop_bounds.rs b/clippy_lints/src/drop_bounds.rs index f496680827913..4ef963ac3148e 100644 --- a/clippy_lints/src/drop_bounds.rs +++ b/clippy_lints/src/drop_bounds.rs @@ -27,6 +27,10 @@ declare_clippy_lint! { /// ```rust /// fn foo() {} /// ``` + /// Could be written as: + /// ```rust + /// fn foo() {} + /// ``` pub DROP_BOUNDS, correctness, "Bounds of the form `T: Drop` are useless" diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index b35a8facf8b99..afefa2506381b 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -22,8 +22,14 @@ declare_clippy_lint! { /// ```rust /// # use std::time::Duration; /// let dur = Duration::new(5, 0); + /// + /// // Bad /// let _micros = dur.subsec_nanos() / 1_000; /// let _millis = dur.subsec_nanos() / 1_000_000; + /// + /// // Good + /// let _micros = dur.subsec_micros(); + /// let _millis = dur.subsec_millis(); /// ``` pub DURATION_SUBSEC, complexity, diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index a5871cf0cd4dd..cb0fd59a2d407 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -25,31 +25,47 @@ declare_clippy_lint! { /// BattenbergCake, /// } /// ``` + /// Could be written as: + /// ```rust + /// enum Cake { + /// BlackForest, + /// Hummingbird, + /// Battenberg, + /// } + /// ``` pub ENUM_VARIANT_NAMES, style, "enums where all variants share a prefix/postfix" } declare_clippy_lint! { - /// **What it does:** Detects enumeration variants that are prefixed or suffixed - /// by the same characters. + /// **What it does:** Detects public enumeration variants that are + /// prefixed or suffixed by the same characters. /// - /// **Why is this bad?** Enumeration variant names should specify their variant, + /// **Why is this bad?** Public enumeration variant names should specify their variant, /// not repeat the enumeration name. /// /// **Known problems:** None. /// /// **Example:** /// ```rust - /// enum Cake { + /// pub enum Cake { /// BlackForestCake, /// HummingbirdCake, /// BattenbergCake, /// } /// ``` + /// Could be written as: + /// ```rust + /// pub enum Cake { + /// BlackForest, + /// Hummingbird, + /// Battenberg, + /// } + /// ``` pub PUB_ENUM_VARIANT_NAMES, pedantic, - "enums where all variants share a prefix/postfix" + "public enums where all variants share a prefix/postfix" } declare_clippy_lint! { @@ -66,6 +82,12 @@ declare_clippy_lint! { /// struct BlackForestCake; /// } /// ``` + /// Could be written as: + /// ```rust + /// mod cake { + /// struct BlackForest; + /// } + /// ``` pub MODULE_NAME_REPETITIONS, pedantic, "type names prefixed/postfixed with their containing module's name" diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 4e1c1f131405f..d7819d737ea04 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -39,7 +39,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```ignore + /// // Bad /// &x == y + /// + /// // Good + /// x == *y /// ``` pub OP_REF, style, diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 1ec60a0e6e67a..7227683aa5ac2 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -28,9 +28,16 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # fn foo(bar: usize) {} + /// + /// // Bad /// let x = Box::new(1); /// foo(*x); /// println!("{}", *x); + /// + /// // Good + /// let x = 1; + /// foo(x); + /// println!("{}", x); /// ``` pub BOXED_LOCAL, perf, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index e3e1136b67693..5f0cd1ec72cee 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -26,7 +26,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,ignore + /// // Bad /// xs.map(|x| foo(x)) + /// + /// // Good + /// foo(xs) /// ``` /// where `foo(_)` is a plain function that takes the exact argument type of /// `x`. diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 5206266ccf2a6..37e24ff34f7ae 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -21,11 +21,17 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let mut x = 0; + /// + /// // Bad /// let a = { /// x = 1; /// 1 /// } + x; /// // Unclear whether a is 1 or 2. + /// + /// // Good + /// x = 1; + /// let a = 1 + x; /// ``` pub EVAL_ORDER_DEPENDENCE, complexity, From 262c9dc025042646610df879dd9708eea625534d Mon Sep 17 00:00:00 2001 From: ThibsG Date: Fri, 29 May 2020 18:15:42 +0200 Subject: [PATCH 541/695] Fix more code examples --- clippy_lints/src/fallible_impl_from.rs | 15 +++++++++++++-- clippy_lints/src/floating_point_arithmetic.rs | 2 -- clippy_lints/src/format.rs | 6 +++++- clippy_lints/src/functions.rs | 14 ++++++++++---- clippy_lints/src/implicit_saturating_sub.rs | 7 ------- clippy_lints/src/int_plus_one.rs | 1 - clippy_lints/src/integer_division.rs | 11 +++++++---- clippy_lints/src/items_after_statements.rs | 16 ++++++++++++++++ 8 files changed, 51 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 17639cc2a0643..575462f25e61d 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -18,13 +18,24 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```rust + /// ```rust,ignore /// struct Foo(i32); + /// + /// // Bad /// impl From for Foo { /// fn from(s: String) -> Self { /// Foo(s.parse().unwrap()) /// } /// } + /// + /// // Good + /// use std::convert::TryFrom; + /// impl TryFrom for Foo { + /// type Error = (); + /// fn try_from(s: String) -> Result { + /// s.parse() + /// } + /// } /// ``` pub FALLIBLE_IMPL_FROM, nursery, @@ -120,7 +131,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it move |diag| { diag.help( "`From` is intended for infallible conversions only. \ - Use `TryFrom` if there's a possibility for the conversion to fail."); + Use `TryFrom` if there's a possibility for the conversion to fail."); diag.span_note(fpu.result, "potential failure(s)"); }); } diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 86317fb8bd5c4..3a912d928375d 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -28,7 +28,6 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// /// let a = 3f32; /// let _ = a.powf(1.0 / 3.0); /// let _ = (1.0 + a).ln(); @@ -38,7 +37,6 @@ declare_clippy_lint! { /// is better expressed as /// /// ```rust - /// /// let a = 3f32; /// let _ = a.cbrt(); /// let _ = a.ln_1p(); diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 5b092526ce4f2..1530538aa7d13 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -25,9 +25,13 @@ declare_clippy_lint! { /// /// **Examples:** /// ```rust + /// + /// // Bad /// # let foo = "foo"; - /// format!("foo"); /// format!("{}", foo); + /// + /// // Good + /// format!("foo"); /// ``` pub USELESS_FORMAT, complexity, diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index c24a24733d7f3..9b5f1dee7f44a 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -49,11 +49,11 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ``` rust + /// ```rust /// fn im_too_long() { - /// println!(""); + /// println!(""); /// // ... 100 more LoC - /// println!(""); + /// println!(""); /// } /// ``` pub TOO_MANY_LINES, @@ -79,10 +79,16 @@ declare_clippy_lint! { /// `some_argument.get_raw_ptr()`). /// /// **Example:** - /// ```rust + /// ```rust,ignore + /// // Bad /// pub fn foo(x: *const u8) { /// println!("{}", unsafe { *x }); /// } + /// + /// // Good + /// pub unsafe fn foo(x: *const u8) { + /// println!("{}", unsafe { *x }); + /// } /// ``` pub NOT_UNSAFE_PTR_ARG_DEREF, correctness, diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 155a93de4facf..fdaf37e5e08fa 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -25,13 +25,6 @@ declare_clippy_lint! { /// if i != 0 { /// i -= 1; /// } - /// ``` - /// Use instead: - /// ```rust - /// let end: u32 = 10; - /// let start: u32 = 5; - /// - /// let mut i: u32 = end - start; /// /// // Good /// i = i.saturating_sub(1); diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index d5dbd495680b2..e91fb0c2f27cd 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -10,7 +10,6 @@ use crate::utils::{snippet_opt, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block /// - /// /// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`. /// /// **Known problems:** None. diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index fe34d33fe652c..d537ef3f3238e 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -15,10 +15,13 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust - /// fn main() { - /// let x = 3 / 2; - /// println!("{}", x); - /// } + /// // Bad + /// let x = 3 / 2; + /// println!("{}", x); + /// + /// // Good + /// let x = 3f32 / 2f32; + /// println!("{}", x); /// ``` pub INTEGER_DIVISION, restriction, diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index e7062b7c16bb9..c8576bcfcb444 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -16,6 +16,7 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// fn foo() { /// println!("cake"); /// } @@ -28,6 +29,21 @@ declare_clippy_lint! { /// foo(); // prints "foo" /// } /// ``` + /// + /// ```rust + /// // Good + /// fn foo() { + /// println!("cake"); + /// } + /// + /// fn main() { + /// fn foo() { + /// println!("foo"); + /// } + /// foo(); // prints "foo" + /// foo(); // prints "foo" + /// } + /// ``` pub ITEMS_AFTER_STATEMENTS, pedantic, "blocks where an item comes after a statement" From 19339334cb4e9c6db5a1f7dced38edcb16707bc7 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 31 May 2020 11:38:48 +0200 Subject: [PATCH 542/695] Give more corrected code examples in doc --- clippy_lints/src/literal_representation.rs | 12 +++++ clippy_lints/src/matches.rs | 44 ++++++++++++++++--- clippy_lints/src/misc.rs | 31 ++++++++++++- clippy_lints/src/misc_early.rs | 34 +++++++++++--- clippy_lints/src/mut_reference.rs | 4 ++ clippy_lints/src/mutex_atomic.rs | 12 ++++- clippy_lints/src/needless_bool.rs | 3 +- clippy_lints/src/needless_borrow.rs | 8 +++- clippy_lints/src/needless_pass_by_value.rs | 3 +- clippy_lints/src/needless_update.rs | 10 +++++ clippy_lints/src/ptr.rs | 23 ++++++---- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/reference.rs | 5 +++ clippy_lints/src/regex.rs | 12 ++--- clippy_lints/src/shadow.rs | 10 +++++ .../src/single_component_path_imports.rs | 4 +- .../src/slow_vector_initialization.rs | 8 +++- clippy_lints/src/strings.rs | 8 ++++ 18 files changed, 195 insertions(+), 38 deletions(-) diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index ec7c4531ed716..7ba43562d7d44 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -24,7 +24,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let x: u64 = 61864918973511; + /// + /// // Good + /// let x: u64 = 61_864_918_973_511; /// ``` pub UNREADABLE_LITERAL, pedantic, @@ -44,7 +48,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Probably mistyped /// 2_32; + /// + /// // Good + /// 2_i32; /// ``` pub MISTYPED_LITERAL_SUFFIXES, correctness, @@ -63,7 +71,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let x: u64 = 618_64_9189_73_511; + /// + /// // Good + /// let x: u64 = 61_864_918_973_511; /// ``` pub INCONSISTENT_DIGIT_GROUPING, style, diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 94380acfcfd4c..146212cb2c7a1 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -36,10 +36,17 @@ declare_clippy_lint! { /// ```rust /// # fn bar(stool: &str) {} /// # let x = Some("abc"); + /// + /// // Bad /// match x { /// Some(ref foo) => bar(foo), /// _ => (), /// } + /// + /// // Good + /// if let Some(ref foo) = x { + /// bar(foo); + /// } /// ``` pub SINGLE_MATCH, style, @@ -97,11 +104,19 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,ignore + /// // Bad /// match x { /// &A(ref y) => foo(y), /// &B => bar(), /// _ => frob(&x), /// } + /// + /// // Good + /// match *x { + /// A(ref y) => foo(y), + /// B => bar(), + /// _ => frob(x), + /// } /// ``` pub MATCH_REF_PATS, style, @@ -197,10 +212,15 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let x: Option<()> = None; + /// + /// // Bad /// let r: Option<&()> = match x { /// None => None, /// Some(ref v) => Some(v), /// }; + /// + /// // Good + /// let r: Option<&()> = x.as_ref(); /// ``` pub MATCH_AS_REF, complexity, @@ -219,10 +239,18 @@ declare_clippy_lint! { /// ```rust /// # enum Foo { A(usize), B(usize) } /// # let x = Foo::B(1); + /// + /// // Bad /// match x { /// Foo::A(_) => {}, /// _ => {}, /// } + /// + /// // Good + /// match x { + /// Foo::A(_) => {}, + /// Foo::B(_) => {}, + /// } /// ``` pub WILDCARD_ENUM_MATCH_ARM, restriction, @@ -242,16 +270,15 @@ declare_clippy_lint! { /// ```rust /// # enum Foo { A, B, C } /// # let x = Foo::B; + /// + /// // Bad /// match x { /// Foo::A => {}, /// Foo::B => {}, /// _ => {}, /// } - /// ``` - /// Use instead: - /// ```rust - /// # enum Foo { A, B, C } - /// # let x = Foo::B; + /// + /// // Good /// match x { /// Foo::A => {}, /// Foo::B => {}, @@ -273,10 +300,17 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// match "foo" { /// "a" => {}, /// "bar" | _ => {}, /// } + /// + /// // Good + /// match "foo" { + /// "a" => {}, + /// _ => {}, + /// } /// ``` pub WILDCARD_IN_OR_PATTERNS, complexity, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index e1d524c2231e4..a3b7134a376d5 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -38,10 +38,16 @@ declare_clippy_lint! { /// dereferences, e.g., changing `*x` to `x` within the function. /// /// **Example:** - /// ```rust + /// ```rust,ignore + /// // Bad /// fn foo(ref x: u8) -> bool { /// true /// } + /// + /// // Good + /// fn foo(x: &u8) -> bool { + /// true + /// } /// ``` pub TOPLEVEL_REF_ARG, style, @@ -60,7 +66,11 @@ declare_clippy_lint! { /// ```rust /// # let x = 1.0; /// + /// // Bad /// if x == f32::NAN { } + /// + /// // Good + /// if x.is_nan() { } /// ``` pub CMP_NAN, correctness, @@ -83,8 +93,15 @@ declare_clippy_lint! { /// ```rust /// let x = 1.2331f64; /// let y = 1.2332f64; + /// + /// // Bad /// if y == 1.23f64 { } /// if y != x {} // where both are floats + /// + /// // Good + /// let error = 0.01f64; // Use an epsilon for comparison + /// if (y - 1.23f64).abs() < error { } + /// if (y - x).abs() > error { } /// ``` pub FLOAT_CMP, correctness, @@ -191,7 +208,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let a = 0 as *const u32; + /// + /// // Good + /// let a = std::ptr::null::(); /// ``` pub ZERO_PTR, style, @@ -214,7 +235,13 @@ declare_clippy_lint! { /// ```rust /// let x: f64 = 1.0; /// const ONE: f64 = 1.00; - /// x == ONE; // where both are floats + /// + /// // Bad + /// if x == ONE { } // where both are floats + /// + /// // Good + /// let error = 0.1f64; // Use an epsilon for comparison + /// if (x - ONE).abs() < error { } /// ``` pub FLOAT_CMP_CONST, restriction, diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 552222eba2ee2..ad39e59d0678a 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -59,7 +59,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// fn foo(a: i32, _a: i32) {} + /// + /// // Good + /// fn bar(a: i32, _b: i32) {} /// ``` pub DUPLICATE_UNDERSCORE_ARGUMENT, style, @@ -77,7 +81,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,ignore - /// (|| 42)() + /// // Bad + /// let a = (|| 42)() + /// + /// // Good + /// let a = 42 /// ``` pub REDUNDANT_CLOSURE_CALL, complexity, @@ -112,7 +120,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// let y = 0x1a9BAcD; + /// + /// // Good + /// let y = 0x1A9BACD; /// ``` pub MIXED_CASE_HEX_LITERALS, style, @@ -129,7 +141,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// let y = 123832i32; + /// + /// // Good + /// let y = 123832_i32; /// ``` pub UNSEPARATED_LITERAL_SUFFIX, pedantic, @@ -207,9 +223,16 @@ declare_clippy_lint! { /// ```rust /// # let v = Some("abc"); /// + /// // Bad + /// match v { + /// Some(x) => (), + /// y @ _ => (), + /// } + /// + /// // Good /// match v { /// Some(x) => (), - /// y @ _ => (), // easier written as `y`, + /// y => (), /// } /// ``` pub REDUNDANT_PATTERN, @@ -235,16 +258,13 @@ declare_clippy_lint! { /// # struct TupleStruct(u32, u32, u32); /// # let t = TupleStruct(1, 2, 3); /// + /// // Bad /// match t { /// TupleStruct(0, .., _) => (), /// _ => (), /// } - /// ``` - /// can be written as - /// ```rust - /// # struct TupleStruct(u32, u32, u32); - /// # let t = TupleStruct(1, 2, 3); /// + /// // Good /// match t { /// TupleStruct(0, ..) => (), /// _ => (), diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 67a1ac78a6777..58a8e1a1064ae 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -16,7 +16,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```ignore + /// // Bad /// my_vec.push(&mut value) + /// + /// // Good + /// my_vec.push(&value) /// ``` pub UNNECESSARY_MUT_PASSED, style, diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 4e1a8be4892e6..78b15afc5a7fa 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -22,9 +22,15 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// # let y = true; + /// + /// // Bad /// # use std::sync::Mutex; - /// # let y = 1; /// let x = Mutex::new(&y); + /// + /// // Good + /// # use std::sync::atomic::AtomicBool; + /// let x = AtomicBool::new(y); /// ``` pub MUTEX_ATOMIC, perf, @@ -46,6 +52,10 @@ declare_clippy_lint! { /// ```rust /// # use std::sync::Mutex; /// let x = Mutex::new(0usize); + /// + /// // Good + /// # use std::sync::atomic::AtomicUsize; + /// let x = AtomicUsize::new(0usize); /// ``` pub MUTEX_INTEGER, nursery, diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index efa77db822dd0..15b129fa09802 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -15,8 +15,7 @@ use rustc_span::Span; declare_clippy_lint! { /// **What it does:** Checks for expressions of the form `if c { true } else { - /// false }` - /// (or vice versa) and suggest using the condition directly. + /// false }` (or vice versa) and suggests using the condition directly. /// /// **Why is this bad?** Redundant code. /// diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 9ee875d7516eb..5880d1d610206 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -18,12 +18,16 @@ declare_clippy_lint! { /// **Why is this bad?** Suggests that the receiver of the expression borrows /// the expression. /// + /// **Known problems:** None. + /// /// **Example:** /// ```rust + /// // Bad /// let x: &i32 = &&&&&&5; - /// ``` /// - /// **Known problems:** None. + /// // Good + /// let x: &i32 = &5; + /// ``` pub NEEDLESS_BORROW, nursery, "taking a reference that is going to be automatically dereferenced" diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 9c508fc0e4a1a..fbdf927b82476 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -40,9 +40,8 @@ declare_clippy_lint! { /// assert_eq!(v.len(), 42); /// } /// ``` - /// + /// should be /// ```rust - /// // should be /// fn foo(v: &[i32]) { /// assert_eq!(v.len(), 42); /// } diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 4b2586877e562..d866bab2f642c 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -21,6 +21,16 @@ declare_clippy_lint! { /// # z: i32, /// # } /// # let zero_point = Point { x: 0, y: 0, z: 0 }; + /// + /// // Bad + /// Point { + /// x: 1, + /// y: 1, + /// z: 1, + /// ..zero_point + /// }; + /// + /// // Ok /// Point { /// x: 1, /// y: 1, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 4eac571f96620..c77b44e0c99c7 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -47,7 +47,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```ignore + /// // Bad /// fn foo(&Vec) { .. } + /// + /// // Good + /// fn foo(&[u32]) { .. } /// ``` pub PTR_ARG, style, @@ -65,9 +69,15 @@ declare_clippy_lint! { /// /// **Example:** /// ```ignore + /// // Bad /// if x == ptr::null { /// .. /// } + /// + /// // Good + /// if x.is_null() { + /// .. + /// } /// ``` pub CMP_NULL, style, @@ -76,19 +86,16 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** This lint checks for functions that take immutable - /// references and return - /// mutable ones. + /// references and return mutable ones. /// /// **Why is this bad?** This is trivially unsound, as one can create two - /// mutable references - /// from the same (immutable!) source. This - /// [error](https://github.com/rust-lang/rust/issues/39465) + /// mutable references from the same (immutable!) source. + /// This [error](https://github.com/rust-lang/rust/issues/39465) /// actually lead to an interim Rust release 1.15.1. /// /// **Known problems:** To be on the conservative side, if there's at least one - /// mutable reference - /// with the output lifetime, this lint will not trigger. In practice, this - /// case is unlikely anyway. + /// mutable reference with the output lifetime, this lint will not trigger. + /// In practice, this case is unlikely anyway. /// /// **Example:** /// ```ignore diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index ea654467b8668..e4361b00fb4c2 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -88,7 +88,7 @@ impl QuestionMark { replacement_str, applicability, ) - } + } } } } diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index d5797468e9d53..fe457aad50e36 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -16,8 +16,13 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust,ignore + /// // Bad /// let a = f(*&mut b); /// let c = *&d; + /// + /// // Good + /// let a = f(b); + /// let c = d; /// ``` pub DEREF_ADDROF, complexity, diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 30084e3e1ffce..a2c35c4267344 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -86,11 +86,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Regex { if let Some(span) = is_expn_of(expr.span, "regex"); then { if !self.spans.contains(&span) { - span_lint(cx, - REGEX_MACRO, - span, - "`regex!(_)` found. \ - Please use `Regex::new(_)`, which is faster for now."); + span_lint( + cx, + REGEX_MACRO, + span, + "`regex!(_)` found. \ + Please use `Regex::new(_)`, which is faster for now." + ); self.spans.insert(span); } self.last = Some(block.hir_id); diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 11360b0ef8495..68c36f9189184 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -25,7 +25,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let x = 1; + /// + /// // Bad /// let x = &x; + /// + /// // Good + /// let y = &x; // use different variable name /// ``` pub SHADOW_SAME, restriction, @@ -77,7 +82,12 @@ declare_clippy_lint! { /// # let y = 1; /// # let z = 2; /// let x = y; + /// + /// // Bad /// let x = z; // shadows the earlier binding + /// + /// // Good + /// let w = z; // use different variable name /// ``` pub SHADOW_UNRELATED, pedantic, diff --git a/clippy_lints/src/single_component_path_imports.rs b/clippy_lints/src/single_component_path_imports.rs index 8d767a7fec88d..2e853e8301d69 100644 --- a/clippy_lints/src/single_component_path_imports.rs +++ b/clippy_lints/src/single_component_path_imports.rs @@ -16,7 +16,7 @@ declare_clippy_lint! { /// /// **Example:** /// - /// ```rust, ignore + /// ```rust,ignore /// use regex; /// /// fn main() { @@ -24,7 +24,7 @@ declare_clippy_lint! { /// } /// ``` /// Better as - /// ```rust, ignore + /// ```rust,ignore /// fn main() { /// regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); /// } diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index fb3706be1c213..a7c4f2c2291f1 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -22,11 +22,17 @@ declare_clippy_lint! { /// ```rust /// # use core::iter::repeat; /// # let len = 4; + /// + /// // Bad /// let mut vec1 = Vec::with_capacity(len); /// vec1.resize(len, 0); /// /// let mut vec2 = Vec::with_capacity(len); - /// vec2.extend(repeat(0).take(len)) + /// vec2.extend(repeat(0).take(len)); + /// + /// // Good + /// let mut vec1 = vec![0; len]; + /// let mut vec2 = vec![0; len]; /// ``` pub SLOW_VECTOR_INITIALIZATION, perf, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 2c51271e312de..f84566ef707a8 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -24,6 +24,10 @@ declare_clippy_lint! { /// ```rust /// let mut x = "Hello".to_owned(); /// x = x + ", World"; + /// + /// // More readable + /// x += ", World"; + /// x.push_str(", World"); /// ``` pub STRING_ADD_ASSIGN, pedantic, @@ -69,7 +73,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// let bs = "a byte string".as_bytes(); + /// + /// // Good + /// let bs = b"a byte string"; /// ``` pub STRING_LIT_AS_BYTES, style, From 9893254dff38c2644612c8465ae9abfa553f4ea3 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 31 May 2020 12:08:41 +0200 Subject: [PATCH 543/695] Add more corrected code for doc --- clippy_lints/src/methods/mod.rs | 65 ++++++++++++++++++++------ clippy_lints/src/misc.rs | 2 +- clippy_lints/src/vec.rs | 10 +++- clippy_lints/src/verbose_file_reads.rs | 1 + clippy_lints/src/wildcard_imports.rs | 12 +++-- clippy_lints/src/write.rs | 22 ++++++++- clippy_lints/src/zero_div_zero.rs | 6 ++- src/lintlist/mod.rs | 2 +- 8 files changed, 95 insertions(+), 25 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 52ca962e7ef97..fbc29efdeb26b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -218,7 +218,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let x = Ok::<_, ()>(()); - /// x.ok().expect("why did I do this again?") + /// + /// // Bad + /// x.ok().expect("why did I do this again?"); + /// + /// // Good + /// x.expect("why did I do this again?"); /// ``` pub OK_EXPECT, style, @@ -273,8 +278,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let opt = Some(1); - /// opt.map_or(None, |a| Some(a + 1)) - /// # ; + /// + /// // Bad + /// opt.map_or(None, |a| Some(a + 1)); + /// + /// // Good + /// opt.and_then(|a| Some(a + 1)); /// ``` pub OPTION_MAP_OR_NONE, style, @@ -390,14 +399,19 @@ declare_clippy_lint! { /// **What it does:** Checks for usage of `_.map(_).flatten(_)`, /// /// **Why is this bad?** Readability, this can be written more concisely as a - /// single method call. + /// single method call using `_.flat_map(_)` /// /// **Known problems:** /// /// **Example:** /// ```rust /// let vec = vec![vec![1]]; + /// + /// // Bad /// vec.iter().map(|x| x.iter()).flatten(); + /// + /// // Good + /// vec.iter().flat_map(|x| x.iter()); /// ``` pub MAP_FLATTEN, pedantic, @@ -417,7 +431,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let vec = vec![1]; + /// + /// // Bad /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2); + /// + /// // Good + /// vec.iter().filter_map(|x| Some(*x * 2)); /// ``` pub FILTER_MAP, pedantic, @@ -634,7 +653,12 @@ declare_clippy_lint! { /// ```rust /// # use std::rc::Rc; /// let x = Rc::new(1); + /// + /// // Bad /// x.clone(); + /// + /// // Good + /// Rc::clone(&x); /// ``` pub CLONE_ON_REF_PTR, restriction, @@ -741,7 +765,12 @@ declare_clippy_lint! { /// **Known problems:** Does not catch multi-byte unicode characters. /// /// **Example:** - /// `_.split("x")` could be `_.split('x')` + /// ```rust,ignore + /// // Bad + /// _.split("x"); + /// + /// // Good + /// _.split('x'); pub SINGLE_CHAR_PATTERN, perf, "using a single-character str where a char could be used, e.g., `_.split(\"x\")`" @@ -964,8 +993,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `.chars().last()` or - /// `.chars().next_back()` on a `str` to check if it ends with a given char. + /// **What it does:** Checks for usage of `_.chars().last()` or + /// `_.chars().next_back()` on a `str` to check if it ends with a given char. /// /// **Why is this bad?** Readability, this can be written more concisely as /// `_.ends_with(_)`. @@ -975,8 +1004,12 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// # let name = "_"; - /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-') - /// # ; + /// + /// // Bad + /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); + /// + /// // Good + /// name.ends_with('_') || name.ends_with('-'); /// ``` pub CHARS_LAST_CMP, style, @@ -1044,17 +1077,15 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); - /// ``` - /// As there is no transformation of the argument this could be written as: - /// ```rust + /// + /// // As there is no transformation of the argument this could be written as: /// let _ = (0..3).filter(|&x| x > 2); /// ``` /// /// ```rust /// let _ = (0..4).filter_map(|x| Some(x + 1)); - /// ``` - /// As there is no conditional check on the argument this could be written as: - /// ```rust + /// + /// // As there is no conditional check on the argument this could be written as: /// let _ = (0..4).map(|x| x + 1); /// ``` pub UNNECESSARY_FILTER_MAP, @@ -1075,7 +1106,11 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust + /// // Bad /// let _ = (&vec![3, 4, 5]).into_iter(); + /// + /// // Good + /// let _ = (&vec![3, 4, 5]).iter(); /// ``` pub INTO_ITER_ON_REF, style, diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index a3b7134a376d5..51282ab93ef6e 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -93,7 +93,7 @@ declare_clippy_lint! { /// ```rust /// let x = 1.2331f64; /// let y = 1.2332f64; - /// + /// /// // Bad /// if y == 1.23f64 { } /// if y != x {} // where both are floats diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 1174f42157749..a8d4c7620b1ef 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -17,8 +17,14 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```rust,ignore - /// foo(&vec![1, 2]) + /// ```rust + /// # fn foo(my_vec: &[u8]) {} + /// + /// // Bad + /// foo(&vec![1, 2]); + /// + /// // Good + /// foo(&[1, 2]); /// ``` pub USELESS_VEC, perf, diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 4d8d4438d881d..7247518e19b9d 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -9,6 +9,7 @@ declare_clippy_lint! { /// /// **Why is this bad?** `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) + /// /// **Known problems:** None. /// /// **Example:** diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs index 32d9a45c37d78..b637253bd0264 100644 --- a/clippy_lints/src/wildcard_imports.rs +++ b/clippy_lints/src/wildcard_imports.rs @@ -19,8 +19,14 @@ declare_clippy_lint! { /// still around. /// /// **Example:** - /// ```rust + /// ```rust,ignore + /// // Bad /// use std::cmp::Ordering::*; + /// foo(Less); + /// + /// // Good + /// use std::cmp::Ordering; + /// foo(Ordering::Less) /// ``` pub ENUM_GLOB_USE, pedantic, @@ -60,15 +66,15 @@ declare_clippy_lint! { /// /// **Example:** /// - /// Bad: /// ```rust,ignore + /// // Bad /// use crate1::*; /// /// foo(); /// ``` /// - /// Good: /// ```rust,ignore + /// // Good /// use crate1::foo; /// /// foo(); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 5f794598052f6..22ce484b24e40 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -23,7 +23,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust + /// // Bad /// println!(""); + /// + /// // Good + /// println!(); /// ``` pub PRINTLN_EMPTY_STRING, style, @@ -32,8 +36,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** This lint warns when you use `print!()` with a format - /// string that - /// ends in a newline. + /// string that ends in a newline. /// /// **Why is this bad?** You should use `println!()` instead, which appends the /// newline. @@ -125,7 +128,12 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); + /// + /// // Bad /// writeln!(buf, ""); + /// + /// // Good + /// writeln!(buf); /// ``` pub WRITELN_EMPTY_STRING, style, @@ -147,7 +155,12 @@ declare_clippy_lint! { /// # use std::fmt::Write; /// # let mut buf = String::new(); /// # let name = "World"; + /// + /// // Bad /// write!(buf, "Hello {}!\n", name); + /// + /// // Good + /// writeln!(buf, "Hello {}!", name); /// ``` pub WRITE_WITH_NEWLINE, style, @@ -168,7 +181,12 @@ declare_clippy_lint! { /// ```rust /// # use std::fmt::Write; /// # let mut buf = String::new(); + /// + /// // Bad /// writeln!(buf, "{}", "foo"); + /// + /// // Good + /// writeln!(buf, "foo"); /// ``` pub WRITE_LITERAL, style, diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index fb4700d8743fd..0820385e01bb5 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -14,7 +14,11 @@ declare_clippy_lint! { /// /// **Example:** /// ```rust - /// 0.0f32 / 0.0; + /// // Bad + /// let nan = 0.0f32 / 0.0; + /// + /// // Good + /// let nan = f32::NAN; /// ``` pub ZERO_DIVIDED_BY_ZERO, complexity, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index ab9542a7b9c8c..6b6e2c7324c26 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1735,7 +1735,7 @@ pub static ref ALL_LINTS: Vec = vec![ Lint { name: "pub_enum_variant_names", group: "pedantic", - desc: "enums where all variants share a prefix/postfix", + desc: "public enums where all variants share a prefix/postfix", deprecation: None, module: "enum_variants", }, From 137a3b4d3242cfe331f8f9b87c51ac0c431fe160 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 1 Jun 2020 10:16:01 +0200 Subject: [PATCH 544/695] Corrected doc PR fixes --- clippy_lints/src/drop_bounds.rs | 2 +- clippy_lints/src/eta_reduction.rs | 2 +- clippy_lints/src/eval_order_dependence.rs | 7 +++++-- clippy_lints/src/fallible_impl_from.rs | 12 ++++++++++-- clippy_lints/src/functions.rs | 2 +- clippy_lints/src/methods/mod.rs | 6 +++++- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/drop_bounds.rs b/clippy_lints/src/drop_bounds.rs index 4ef963ac3148e..5a7f759486edd 100644 --- a/clippy_lints/src/drop_bounds.rs +++ b/clippy_lints/src/drop_bounds.rs @@ -29,7 +29,7 @@ declare_clippy_lint! { /// ``` /// Could be written as: /// ```rust - /// fn foo() {} + /// fn foo() {} /// ``` pub DROP_BOUNDS, correctness, diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 5f0cd1ec72cee..d093025fd3d7a 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -30,7 +30,7 @@ declare_clippy_lint! { /// xs.map(|x| foo(x)) /// /// // Good - /// foo(xs) + /// xs.map(foo) /// ``` /// where `foo(_)` is a plain function that takes the exact argument type of /// `x`. diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 37e24ff34f7ae..74144fb299de2 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -30,8 +30,11 @@ declare_clippy_lint! { /// // Unclear whether a is 1 or 2. /// /// // Good - /// x = 1; - /// let a = 1 + x; + /// let tmp = { + /// x = 1; + /// 1 + /// }; + /// let a = tmp + x; /// ``` pub EVAL_ORDER_DEPENDENCE, complexity, diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 575462f25e61d..92812816461c5 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -18,7 +18,7 @@ declare_clippy_lint! { /// **Known problems:** None. /// /// **Example:** - /// ```rust,ignore + /// ```rust /// struct Foo(i32); /// /// // Bad @@ -27,13 +27,21 @@ declare_clippy_lint! { /// Foo(s.parse().unwrap()) /// } /// } + /// ``` /// + /// ```rust /// // Good + /// struct Foo(i32); + /// /// use std::convert::TryFrom; /// impl TryFrom for Foo { /// type Error = (); /// fn try_from(s: String) -> Result { - /// s.parse() + /// if let Ok(parsed) = s.parse() { + /// Ok(Foo(parsed)) + /// } else { + /// Err(()) + /// } /// } /// } /// ``` diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 9b5f1dee7f44a..325b6cf32a3d2 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -52,7 +52,7 @@ declare_clippy_lint! { /// ```rust /// fn im_too_long() { /// println!(""); - /// // ... 100 more LoC + /// // ... 100 more LoC /// println!(""); /// } /// ``` diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fbc29efdeb26b..a8d5c10d5daac 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -436,7 +436,11 @@ declare_clippy_lint! { /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2); /// /// // Good - /// vec.iter().filter_map(|x| Some(*x * 2)); + /// vec.iter().filter_map(|x| if *x == 0 { + /// Some(*x * 2) + /// } else { + /// None + /// }); /// ``` pub FILTER_MAP, pedantic, From 576a97b6d1add4da03cec36adafbea3084456ed8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 1 Jun 2020 13:07:29 +0200 Subject: [PATCH 545/695] Clean up E0637 explanation --- src/librustc_error_codes/error_codes/E0637.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0637.md b/src/librustc_error_codes/error_codes/E0637.md index e114d3d0f94ae..d9068950bdfee 100644 --- a/src/librustc_error_codes/error_codes/E0637.md +++ b/src/librustc_error_codes/error_codes/E0637.md @@ -1,6 +1,7 @@ An underscore `_` character has been used as the identifier for a lifetime. -Erroneous example: +Erroneous code example: + ```compile_fail,E0106,E0637 fn longest<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { //^^ `'_` is a reserved lifetime name @@ -11,6 +12,7 @@ fn longest<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str { } } ``` + `'_`, cannot be used as a lifetime identifier because it is a reserved for the anonymous lifetime. To fix this, use a lowercase letter such as 'a, or a series of lowercase letters such as `'foo`. For more information, see [the @@ -18,6 +20,7 @@ book][bk-no]. For more information on using the anonymous lifetime in rust nightly, see [the nightly book][bk-al]. Corrected example: + ``` fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str { if str1.len() > str2.len() { From 664222a4e2223e5b6505d027b36b4deebb9865ac Mon Sep 17 00:00:00 2001 From: Konrad Borowski Date: Mon, 1 Jun 2020 15:36:45 +0200 Subject: [PATCH 546/695] Remove allow missing_debug_implementations for MaybeUninit It already has a Debug implementation. --- src/libcore/mem/maybe_uninit.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 01c97444ae3ae..499016545e967 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -214,7 +214,6 @@ use crate::mem::ManuallyDrop; /// remain `#[repr(transparent)]`. That said, `MaybeUninit` will *always* guarantee that it has /// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that /// guarantee may evolve. -#[allow(missing_debug_implementations)] #[stable(feature = "maybe_uninit", since = "1.36.0")] // Lang item so we can wrap other types in it. This is useful for generators. #[lang = "maybe_uninit"] From d8cc2c1e4f8fa6bd49fe9c395353f9e24c7b51fc Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Mon, 1 Jun 2020 16:19:10 +0200 Subject: [PATCH 547/695] Add a warning about infinite reading in read_(until|line) --- src/libstd/io/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index ebe6d09023f42..717d2868abf98 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1883,6 +1883,10 @@ pub trait BufRead: Read { /// /// If successful, this function will return the total number of bytes read. /// + /// This function is blocking and should be used carefully: it is possible for + /// an attacker to continuously send bytes without ever sending the delimiter + /// or EOF. + /// /// # Errors /// /// This function will ignore all instances of [`ErrorKind::Interrupted`] and @@ -1945,6 +1949,10 @@ pub trait BufRead: Read { /// /// If this function returns `Ok(0)`, the stream has reached EOF. /// + /// This function is blocking and should be used carefully: it is possible for + /// an attacker to continuously send bytes without ever sending a newline + /// or EOF. + /// /// # Errors /// /// This function has the same error semantics as [`read_until`] and will From 0fd9a37ff452a9a32a2cbab9273bc964f0f047f3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 1 Jun 2020 08:33:07 -0700 Subject: [PATCH 548/695] rustc: Remove the `--passive-segments` LLD flag on wasm This flag looks like it's been removed in LLVM 10, so this removes rustc unconditionally passing the flag. --- src/librustc_codegen_ssa/back/linker.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 46c365efdb5fa..77cb31bf3d278 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -1010,9 +1010,6 @@ impl<'a> WasmLd<'a> { // sharing memory and instantiating the module multiple times. As a // result if it were exported then we'd just have no sharing. // - // * `--passive-segments` - all memory segments should be passive to - // prevent each module instantiation from reinitializing memory. - // // * `--export=__wasm_init_memory` - when using `--passive-segments` the // linker will synthesize this function, and so we need to make sure // that our usage of `--export` below won't accidentally cause this @@ -1026,7 +1023,6 @@ impl<'a> WasmLd<'a> { cmd.arg("--shared-memory"); cmd.arg("--max-memory=1073741824"); cmd.arg("--import-memory"); - cmd.arg("--passive-segments"); cmd.arg("--export=__wasm_init_memory"); cmd.arg("--export=__wasm_init_tls"); cmd.arg("--export=__tls_size"); From eb8d9002fa3802ebb78d6854ddec207cbaf6aa18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 May 2020 18:20:37 -0700 Subject: [PATCH 549/695] Add test for #72554. --- src/test/ui/issues/issue-72554.rs | 20 ++++++++++++++++++++ src/test/ui/issues/issue-72554.stderr | 13 +++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/test/ui/issues/issue-72554.rs create mode 100644 src/test/ui/issues/issue-72554.stderr diff --git a/src/test/ui/issues/issue-72554.rs b/src/test/ui/issues/issue-72554.rs new file mode 100644 index 0000000000000..47aca05d7786f --- /dev/null +++ b/src/test/ui/issues/issue-72554.rs @@ -0,0 +1,20 @@ +use std::collections::BTreeSet; + +#[derive(Hash)] +pub enum ElemDerived { //~ ERROR recursive type `ElemDerived` has infinite size + A(ElemDerived) +} + +pub enum Elem { + Derived(ElemDerived) +} + +pub struct Set(BTreeSet); + +impl Set { + pub fn into_iter(self) -> impl Iterator { + self.0.into_iter() + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr new file mode 100644 index 0000000000000..9db65f4a2ee8f --- /dev/null +++ b/src/test/ui/issues/issue-72554.stderr @@ -0,0 +1,13 @@ +error[E0072]: recursive type `ElemDerived` has infinite size + --> $DIR/issue-72554.rs:4:1 + | +LL | pub enum ElemDerived { + | ^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size +LL | A(ElemDerived) + | ----------- recursive without indirection + | + = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ElemDerived` representable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. From b2c44696ad792bc2a2b2ee76e74e7dfdbef80e98 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 1 Jun 2020 17:03:47 +0000 Subject: [PATCH 550/695] Add associated consts MIN/MAX for Wrapping --- src/libcore/num/wrapping.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 82fa6acfbd62a..bb648ba8c25de 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -337,14 +337,10 @@ Basic usage: #![feature(wrapping_int_impl)] use std::num::Wrapping; -assert_eq!(>::min_value(), ", -"Wrapping(", stringify!($t), "::min_value())); +assert_eq!(>::MIN, Wrapping(", stringify!($t), "::MIN)); ```"), #[unstable(feature = "wrapping_int_impl", issue = "32463")] - #[inline] - pub const fn min_value() -> Self { - Wrapping(<$t>::min_value()) - } + pub const MIN: Self = Self(<$t>::MIN); } doc_comment! { @@ -358,14 +354,10 @@ Basic usage: #![feature(wrapping_int_impl)] use std::num::Wrapping; -assert_eq!(>::max_value(), ", -"Wrapping(", stringify!($t), "::max_value())); +assert_eq!(>::MAX, Wrapping(", stringify!($t), "::MAX)); ```"), #[unstable(feature = "wrapping_int_impl", issue = "32463")] - #[inline] - pub const fn max_value() -> Self { - Wrapping(<$t>::max_value()) - } + pub const MAX: Self = Self(<$t>::MAX); } doc_comment! { From 9e89ba93fda29b4dc707cd14bd518b73e676d895 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 31 May 2020 15:09:58 +0200 Subject: [PATCH 551/695] Add doc for checking if type defines certain method --- doc/common_tools_writing_lints.md | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md index ed33b37c6bd1b..dbc434505947d 100644 --- a/doc/common_tools_writing_lints.md +++ b/doc/common_tools_writing_lints.md @@ -4,7 +4,9 @@ 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) + - [Checking if an expression is calling a specific method](#checking-if-an-expr-is-calling-a-specific-method) - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait) + - [Checking if a type defines a method](#checking-if-a-type-defines-a-method) - [Dealing with macros](#dealing-with-macros) Useful Rustc dev guide links: @@ -49,6 +51,26 @@ Two noticeable items here: - `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step, it includes useful information such as types of expressions, ways to resolve methods and so on. +# Checking if an expr is calling a specific method + +Starting with an `expr`, you can check whether it is calling a specific method `some_method`: + +```rust +impl LateLintPass<'_, '_> for MyStructLint { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) { + if_chain! { + // Check our expr is calling a method + if let hir::ExprKind::MethodCall(path, _, _args) = &expr.kind; + // Check the name of this method is `some_method` + if path.ident.name == sym!(some_method); + then { + // ... + } + } + } +} +``` + # Checking if a type implements a specific trait There are two ways to do this, depending if the target trait is part of lang items. @@ -83,6 +105,32 @@ A list of defined paths for Clippy can be found in [paths.rs][paths] We access lang items through the type context `tcx`. `tcx` is of type [`TyCtxt`][TyCtxt] and is defined in the `rustc_middle` crate. +# Checking if a type defines a specific method + +To check if our type defines a method called `some_method`: + +```rust +use crate::utils::{is_type_diagnostic_item, return_ty}; + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MyTypeImpl { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx ImplItem<'_>) { + if_chain! { + // Check if item is a method/function + if let ImplItemKind::Fn(ref signature, _) = impl_item.kind; + // Check the method is named `some_method` + if impl_item.ident.name == sym!(some_method); + // We can also check it has a parameter `self` + if signature.decl.implicit_self.has_implicit_self(); + // We can go further and even check if its return type is `String` + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type)); + then { + // ... + } + } + } +} +``` + # Dealing with macros There are several helpers in Clippy's utils to deal with macros: From fd76d236e42378d0feaf5df6dbdbd2db89ba0f1f Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 1 Jun 2020 10:52:07 -0700 Subject: [PATCH 552/695] Use `bug!` instead of `panic!` Co-authored-by: varkor --- src/librustc_typeck/astconv.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9b47c4c7dde70..7173ed3d24ec8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -489,7 +489,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "lifetime" => ParamKindOrd::Lifetime, "type" => ParamKindOrd::Type, "constant" => ParamKindOrd::Const, - _ => panic!(), + // It's more concise to match on the string representation, though it means + // the match is non-exhaustive. + _ => bug!("invalid generic parameter kind"), }; let arg_ord = match arg { GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, From 759e495bbf33dd510deb7aa645622f8f4388b406 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jun 2020 20:17:20 +0200 Subject: [PATCH 553/695] bump Miri, update for cargo-miri being a separate project --- Cargo.lock | 25 ++++++++++++++++--------- Cargo.toml | 1 + src/bootstrap/builder.rs | 2 ++ src/bootstrap/test.rs | 15 +++++++++++---- src/bootstrap/tool.rs | 4 +++- src/tools/miri | 2 +- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 467ef60f2aa26..6cfedd4a56da8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -345,6 +345,19 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "cargo-miri" +version = "0.1.0" +dependencies = [ + "cargo_metadata 0.9.1", + "directories", + "rustc-workspace-hack", + "rustc_version", + "serde", + "serde_json", + "vergen", +] + [[package]] name = "cargo-platform" version = "0.1.1" @@ -2220,22 +2233,17 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder", - "cargo_metadata 0.9.1", "colored", "compiletest_rs", - "directories", "env_logger 0.7.1", "getrandom", "hex 0.4.0", + "libc", "log", - "num-traits", "rand 0.7.3", "rustc-workspace-hack", "rustc_version", - "serde", - "serde_json", "shell-escape", - "vergen", ] [[package]] @@ -5555,13 +5563,12 @@ checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" [[package]] name = "vergen" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" +checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" dependencies = [ "bitflags", "chrono", - "failure", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 7b5e0fa1c2817..f2177a99a9b88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "src/tools/rls", "src/tools/rustfmt", "src/tools/miri", + "src/tools/miri/cargo-miri", "src/tools/rustdoc-themes", "src/tools/unicode-table-generator", "src/tools/expand-yaml-anchors", diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index c8a85eae252ff..ffdd8485181f4 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -344,10 +344,12 @@ impl<'a> Builder<'a> { tool::Rls, tool::Rustdoc, tool::Clippy, + tool::CargoClippy, native::Llvm, native::Sanitizers, tool::Rustfmt, tool::Miri, + tool::CargoMiri, native::Lld ), Kind::Check | Kind::Clippy | Kind::Fix | Kind::Format => { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f1305e2540b4c..9f305ea4729c5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -360,7 +360,12 @@ impl Step for Miri { let miri = builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() }); - if let Some(miri) = miri { + let cargo_miri = builder.ensure(tool::CargoMiri { + compiler, + target: self.host, + extra_features: Vec::new(), + }); + if let (Some(miri), Some(_cargo_miri)) = (miri, cargo_miri) { let mut cargo = builder.cargo(compiler, Mode::ToolRustc, host, "install"); cargo.arg("xargo"); // Configure `cargo install` path. cargo adds a `bin/`. @@ -378,14 +383,16 @@ impl Step for Miri { Mode::ToolRustc, host, "run", - "src/tools/miri", + "src/tools/miri/cargo-miri", SourceType::Submodule, &[], ); - cargo.arg("--bin").arg("cargo-miri").arg("--").arg("miri").arg("setup"); + cargo.arg("--").arg("miri").arg("setup"); // Tell `cargo miri setup` where to find the sources. cargo.env("XARGO_RUST_SRC", builder.src.join("src")); + // Tell it where to find Miri. + cargo.env("MIRI", &miri); // Debug things. cargo.env("RUST_BACKTRACE", "1"); // Overwrite bootstrap's `rustc` wrapper overwriting our flags. @@ -437,7 +444,7 @@ impl Step for Miri { // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", miri_sysroot); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); - cargo.env("MIRI_PATH", miri); + cargo.env("MIRI", miri); cargo.arg("--").args(builder.config.cmd.test_args()); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 5f58f00a2a24d..6cd9f9029c948 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -649,12 +649,14 @@ macro_rules! tool_extended { } } +// Note: tools need to be also added to `Builder::get_step_descriptions` in `build.rs` +// to make `./x.py build ` work. tool_extended!((self, builder), Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {}; CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", {}; Clippy, clippy, "src/tools/clippy", "clippy-driver", {}; Miri, miri, "src/tools/miri", "miri", {}; - CargoMiri, miri, "src/tools/miri", "cargo-miri", {}; + CargoMiri, miri, "src/tools/miri/cargo-miri", "cargo-miri", {}; Rls, rls, "src/tools/rls", "rls", { builder.ensure(Clippy { compiler: self.compiler, diff --git a/src/tools/miri b/src/tools/miri index a6c28f08458e1..faff9a7ad9f2d 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit a6c28f08458e15cead0e80f3b5b7009786bce4a4 +Subproject commit faff9a7ad9f2d07c1702bd8be392134d27e3eaf8 From a44fa387efff44414c7baac249dcd148b93e2eb1 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 1 Jun 2020 09:26:40 +0200 Subject: [PATCH 554/695] Update documentation on changelog updates --- CHANGELOG.md | 19 ++++++++++--------- doc/changelog_update.md | 9 +++++---- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcc9895dd901d..dd0905e9f3990 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,17 +31,17 @@ Current beta, release 2020-07-16 * Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408) * Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622) * Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599) -* Generalize [`option_and_then_some`] and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529) -* Rename [`identity_conversion`] to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568) -* Merge [`block_in_if_condition_expr`] and [`block_in_if_condition_stmt`] into [`blocks_in_if_conditions`]. +* Generalize `option_and_then_some` and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529) +* Rename `identity_conversion` to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568) +* Merge `block_in_if_condition_expr` and `block_in_if_condition_stmt` into [`blocks_in_if_conditions`]. [#5563](https://github.com/rust-lang/rust-clippy/pull/5563) -* Merge [`option_map_unwrap_or`], [`option_map_unwrap_or_else`] and [`result_map_unwrap_or_else`] into [`map_unwrap_or`]. +* Merge `option_map_unwrap_or`, `option_map_unwrap_or_else` and `result_map_unwrap_or_else` into [`map_unwrap_or`]. [#5563](https://github.com/rust-lang/rust-clippy/pull/5563) -* Merge [`option_unwrap_used`] and [`result_unwrap_used`] into [`unwrap_used`]. +* Merge `option_unwrap_used` and `result_unwrap_used` into [`unwrap_used`]. [#5563](https://github.com/rust-lang/rust-clippy/pull/5563) -* Merge [`option_expect_used`] and [`result_expect_used`] into [`expect_used`]. +* Merge `option_expect_used` and `result_expect_used` into [`expect_used`]. [#5563](https://github.com/rust-lang/rust-clippy/pull/5563) -* Merge [`for_loop_over_option`] and [`for_loop_over_result`] into [`for_loops_over_fallibles`]. +* Merge `for_loop_over_option` and `for_loop_over_result` into [`for_loops_over_fallibles`]. [#5563](https://github.com/rust-lang/rust-clippy/pull/5563) ### Enhancements @@ -61,10 +61,11 @@ Current beta, release 2020-07-16 * Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491) * Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602) * Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564) -* Add ignores to the list of words of [`clippy::doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611) +* Add ignores to the list of words of [`doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611) * Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636) * Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647) -* Honor lint level attributes for [`redundant_field_names`] and [`non_expressive_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651) +* Honor lint level attributes for [`redundant_field_names`], [`just_underscores_and_digits`], [`many_single_char_names`] +and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651) * Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429) ### Suggestion Improvements diff --git a/doc/changelog_update.md b/doc/changelog_update.md index 0b80cce6d23ea..edba3b4741cb9 100644 --- a/doc/changelog_update.md +++ b/doc/changelog_update.md @@ -32,8 +32,9 @@ bullet points might be helpful: need to select the Rust release tag from the dropdown and then check the commit of the Clippy directory: - ![Explanation of how to find the commit hash](https://user-images.githubusercontent.com/2042399/62846160-1f8b0480-bcce-11e9-9da8-7964ca034e7a.png) - +To find the commit hash, click on "History" of the relevant branch in github +and search for the latest "Merge commit '' into " commit. +The part is then the most recent commit in the clippy repo. ### 2. Fetching the PRs between those commits @@ -74,5 +75,5 @@ relevant commit ranges. [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md [forge]: https://forge.rust-lang.org/ -[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools -[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools +[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy +[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy From d022603a45358b7421d62161a685b8deb4f45e77 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jun 2020 20:53:45 +0200 Subject: [PATCH 555/695] test miri-unleash TLS accesses --- src/librustc_middle/mir/interpret/error.rs | 4 ++-- src/librustc_mir/transform/check_consts/ops.rs | 5 ----- .../transform/check_consts/validation.rs | 6 +----- src/test/ui/consts/miri_unleashed/inline_asm.rs | 11 +++++++++-- .../ui/consts/miri_unleashed/inline_asm.stderr | 13 ++++++++++++- src/test/ui/consts/miri_unleashed/tls.rs | 17 +++++++++++++++++ src/test/ui/consts/miri_unleashed/tls.stderr | 17 +++++++++++++++++ 7 files changed, 58 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/consts/miri_unleashed/tls.rs create mode 100644 src/test/ui/consts/miri_unleashed/tls.stderr diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs index 7600bf96e1b17..1b3ede40f023a 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/src/librustc_middle/mir/interpret/error.rs @@ -523,12 +523,12 @@ impl fmt::Display for UnsupportedOpInfo { match self { Unsupported(ref msg) => write!(f, "{}", msg), ReadForeignStatic(did) => { - write!(f, "cannot read from foreign (extern) static {:?}", did) + write!(f, "cannot read from foreign (extern) static ({:?})", did) } NoMirFor(did) => write!(f, "no MIR body is available for {:?}", did), ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes",), ReadBytesAsPointer => write!(f, "unable to turn bytes into a pointer"), - ThreadLocalStatic(did) => write!(f, "accessing thread local static {:?}", did), + ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did), } } } diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 28743ee8e3636..92bd740e27aa6 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -12,9 +12,6 @@ use super::ConstCx; /// An operation that is not *always* allowed in a const context. pub trait NonConstOp: std::fmt::Debug { - /// Whether this operation can be evaluated by miri. - const IS_SUPPORTED_IN_MIRI: bool = true; - /// Returns the `Symbol` corresponding to the feature gate that would enable this operation, /// or `None` if such a feature gate does not exist. fn feature_gate() -> Option { @@ -356,8 +353,6 @@ impl NonConstOp for StaticAccess { #[derive(Debug)] pub struct ThreadLocalAccess; impl NonConstOp for ThreadLocalAccess { - const IS_SUPPORTED_IN_MIRI: bool = false; - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { struct_span_err!( ccx.tcx.sess, diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 354fd200fc594..1137c813470be 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -244,11 +244,7 @@ impl Validator<'mir, 'tcx> { return; } - // If an operation is supported in miri it can be turned on with - // `-Zunleash-the-miri-inside-of-you`. - let is_unleashable = O::IS_SUPPORTED_IN_MIRI; - - if is_unleashable && self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { + if self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { self.tcx.sess.miri_unleashed_feature(span, O::feature_gate()); return; } diff --git a/src/test/ui/consts/miri_unleashed/inline_asm.rs b/src/test/ui/consts/miri_unleashed/inline_asm.rs index 7b2b1ed4965f2..aa9b3144f401b 100644 --- a/src/test/ui/consts/miri_unleashed/inline_asm.rs +++ b/src/test/ui/consts/miri_unleashed/inline_asm.rs @@ -1,15 +1,22 @@ // compile-flags: -Zunleash-the-miri-inside-of-you // only-x86_64 -#![feature(llvm_asm)] +#![feature(asm,llvm_asm)] #![allow(const_err)] fn main() {} // Make sure we catch executing inline assembly. -static TEST_BAD: () = { +static TEST_BAD1: () = { unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); } //~^ ERROR could not evaluate static initializer //~| NOTE inline assembly is not supported //~| NOTE in this expansion of llvm_asm! //~| NOTE in this expansion of llvm_asm! }; + +// Make sure we catch executing inline assembly. +static TEST_BAD2: () = { + unsafe { asm!("nop"); } + //~^ ERROR could not evaluate static initializer + //~| NOTE inline assembly is not supported +}; diff --git a/src/test/ui/consts/miri_unleashed/inline_asm.stderr b/src/test/ui/consts/miri_unleashed/inline_asm.stderr index 0f5ee5de39634..d372b4a5d25c0 100644 --- a/src/test/ui/consts/miri_unleashed/inline_asm.stderr +++ b/src/test/ui/consts/miri_unleashed/inline_asm.stderr @@ -6,6 +6,12 @@ LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); } | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0080]: could not evaluate static initializer + --> $DIR/inline_asm.rs:19:14 + | +LL | unsafe { asm!("nop"); } + | ^^^^^^^^^^^^ inline assembly is not supported + warning: skipping const checks | help: skipping check that does not even have a feature gate @@ -13,8 +19,13 @@ help: skipping check that does not even have a feature gate | LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/inline_asm.rs:19:14 + | +LL | unsafe { asm!("nop"); } + | ^^^^^^^^^^^^ = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/miri_unleashed/tls.rs b/src/test/ui/consts/miri_unleashed/tls.rs new file mode 100644 index 0000000000000..27cb802823525 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/tls.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(thread_local)] +#![allow(const_err)] + +use std::thread; + +#[thread_local] +static A: u8 = 0; + +// Make sure we catch executing inline assembly. +static TEST_BAD: () = { + unsafe { let _val = A; } + //~^ ERROR could not evaluate static initializer + //~| NOTE cannot access thread local static +}; + +fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr new file mode 100644 index 0000000000000..d3e87f319acde --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/tls.stderr @@ -0,0 +1,17 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/tls.rs:12:25 + | +LL | unsafe { let _val = A; } + | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A[0])) + +warning: skipping const checks + | +help: skipping check that does not even have a feature gate + --> $DIR/tls.rs:12:25 + | +LL | unsafe { let _val = A; } + | ^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. From eaa57cfb712e0e61bbc61d2309c0fa708f4f297b Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 23 May 2020 11:11:20 -0700 Subject: [PATCH 556/695] `PolyTraitRef::self_ty` returns `Binder` --- src/librustc_middle/ty/sty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index f4962ced6c03a..f01b9751c406b 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -765,8 +765,8 @@ impl<'tcx> TraitRef<'tcx> { pub type PolyTraitRef<'tcx> = Binder>; impl<'tcx> PolyTraitRef<'tcx> { - pub fn self_ty(&self) -> Ty<'tcx> { - self.skip_binder().self_ty() + pub fn self_ty(&self) -> Binder> { + self.map_bound_ref(|tr| tr.self_ty()) } pub fn def_id(&self) -> DefId { From b4e06b9e8899ed907a57d4ecea9dd1be6896a852 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 23 May 2020 11:12:06 -0700 Subject: [PATCH 557/695] Call `skip_binder` or `no_bound_vars` before `self_ty` --- .../traits/error_reporting/mod.rs | 32 ++++++++++++------- .../traits/error_reporting/suggestions.rs | 24 ++++++++++---- .../traits/specialize/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustdoc/clean/mod.rs | 4 +-- .../clippy_lints/src/future_not_send.rs | 2 +- 6 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f8b33b782c017..3c9665e4c1414 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -289,7 +289,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ( Some(format!( "`?` couldn't convert the error to `{}`", - trait_ref.self_ty(), + trait_ref.skip_binder().self_ty(), )), Some( "the question mark operation (`?`) implicitly performs a \ @@ -339,7 +339,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(ret_span) = self.return_type_span(obligation) { err.span_label( ret_span, - &format!("expected `{}` because of this", trait_ref.self_ty()), + &format!( + "expected `{}` because of this", + trait_ref.skip_binder().self_ty() + ), ); } } @@ -352,7 +355,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { "{}the trait `{}` is not implemented for `{}`", pre_message, trait_ref.print_only_trait_path(), - trait_ref.self_ty(), + trait_ref.skip_binder().self_ty(), ) }; @@ -642,7 +645,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - let found_trait_ty = found_trait_ref.self_ty(); + let found_trait_ty = match found_trait_ref.self_ty().no_bound_vars() { + Some(ty) => ty, + None => return, + }; let found_did = match found_trait_ty.kind { ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), @@ -1359,11 +1365,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ) { let get_trait_impl = |trait_def_id| { let mut trait_impl = None; - self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| { - if trait_impl.is_none() { - trait_impl = Some(impl_def_id); - } - }); + self.tcx.for_each_relevant_impl( + trait_def_id, + trait_ref.skip_binder().self_ty(), + |impl_def_id| { + if trait_impl.is_none() { + trait_impl = Some(impl_def_id); + } + }, + ); trait_impl }; let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); @@ -1434,7 +1444,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let mut err = match predicate.kind() { ty::PredicateKind::Trait(ref data, _) => { let trait_ref = data.to_poly_trait_ref(); - let self_ty = trait_ref.self_ty(); + let self_ty = trait_ref.skip_binder().self_ty(); debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); if predicate.references_error() { @@ -1552,7 +1562,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } ty::PredicateKind::Projection(ref data) => { let trait_ref = data.to_poly_trait_ref(self.tcx); - let self_ty = trait_ref.self_ty(); + let self_ty = trait_ref.skip_binder().self_ty(); let ty = data.skip_binder().ty; if predicate.references_error() { return; diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index cfbea9ee0f196..501cde40d245e 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -318,7 +318,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, body_id: hir::HirId, ) { - let self_ty = trait_ref.self_ty(); + let self_ty = trait_ref.skip_binder().self_ty(); let (param_ty, projection) = match &self_ty.kind { ty::Param(_) => (true, None), ty::Projection(projection) => (false, Some(projection)), @@ -524,7 +524,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: &ty::Binder>, points_at_arg: bool, ) { - let self_ty = trait_ref.self_ty(); + let self_ty = match trait_ref.self_ty().no_bound_vars() { + None => return, + Some(ty) => ty, + }; + let (def_id, output_ty, callable) = match self_ty.kind { ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"), ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"), @@ -707,7 +711,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - let mut suggested_ty = trait_ref.self_ty(); + let mut suggested_ty = match trait_ref.self_ty().no_bound_vars() { + Some(ty) => ty, + None => return, + }; for refs_remaining in 0..refs_number { if let ty::Ref(_, inner_ty, _) = suggested_ty.kind { @@ -829,6 +836,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span: Span, trait_ref: &ty::Binder>, ) { + let is_empty_tuple = + |ty: ty::Binder>| ty.skip_binder().kind == ty::Tuple(ty::List::empty()); + let hir = self.tcx.hir(); let parent_node = hir.get_parent_node(obligation.cause.body_id); let node = hir.find(parent_node); @@ -840,7 +850,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let hir::ExprKind::Block(blk, _) = &body.value.kind { if sig.decl.output.span().overlaps(span) && blk.expr.is_none() - && "()" == &trait_ref.self_ty().to_string() + && is_empty_tuple(trait_ref.self_ty()) { // FIXME(estebank): When encountering a method with a trait // bound not satisfied in the return type with a body that has @@ -1271,7 +1281,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ObligationCauseCode::DerivedObligation(derived_obligation) | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => { - let ty = derived_obligation.parent_trait_ref.self_ty(); + let ty = derived_obligation.parent_trait_ref.skip_binder().self_ty(); debug!( "maybe_note_obligation_cause_for_async_await: \ parent_trait_ref={:?} self_ty.kind={:?}", @@ -1911,7 +1921,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let impls_future = self.tcx.type_implements_trait(( future_trait, - self_ty, + self_ty.skip_binder(), ty::List::empty(), obligation.param_env, )); @@ -1927,7 +1937,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let projection_ty = ty::ProjectionTy { // `T` substs: self.tcx.mk_substs_trait( - trait_ref.self_ty(), + trait_ref.self_ty().skip_binder(), self.fresh_substs_for_item(span, item_def_id), ), // `Future::Output` diff --git a/src/librustc_trait_selection/traits/specialize/mod.rs b/src/librustc_trait_selection/traits/specialize/mod.rs index f2b43754acaea..2b596be954267 100644 --- a/src/librustc_trait_selection/traits/specialize/mod.rs +++ b/src/librustc_trait_selection/traits/specialize/mod.rs @@ -496,7 +496,7 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option for (p, _) in predicates { if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() { if Some(poly_trait_ref.def_id()) == sized_trait { - types_without_default_bounds.remove(poly_trait_ref.self_ty()); + types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder()); continue; } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8fa65a135ac2..4e76fd4ca11fb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3812,7 +3812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, expected_vid: ty::TyVid, ) -> bool { - let self_ty = self.shallow_resolve(trait_ref.self_ty()); + let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); debug!( "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", trait_ref, self_ty, expected_vid diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 371df7444b004..dd4df11b1df38 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -500,7 +500,7 @@ impl<'a> Clean for ty::PolyTraitPredicate<'a> { fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { let poly_trait_ref = self.map_bound(|pred| pred.trait_ref); WherePredicate::BoundPredicate { - ty: poly_trait_ref.self_ty().clean(cx), + ty: poly_trait_ref.skip_binder().self_ty().clean(cx), bounds: vec![poly_trait_ref.clean(cx)], } } @@ -755,7 +755,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx let mut projection = None; let param_idx = (|| { if let Some(trait_ref) = p.to_opt_poly_trait_ref() { - if let ty::Param(param) = trait_ref.self_ty().kind { + if let ty::Param(param) = trait_ref.skip_binder().self_ty().kind { return Some(param.index); } } else if let Some(outlives) = p.to_opt_type_outlives() { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 0a02aa7533c17..17dd3cd5493e7 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FutureNotSend { let trait_ref = trait_pred.to_poly_trait_ref(); db.note(&*format!( "`{}` doesn't implement `{}`", - trait_ref.self_ty(), + trait_ref.skip_binder().self_ty(), trait_ref.print_only_trait_path(), )); } From ea06c72fddd6d3b12a5a9f955f80faadac9918e0 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sat, 23 May 2020 11:12:06 -0700 Subject: [PATCH 558/695] Call `skip_binder` or `no_bound_vars` before `self_ty` --- clippy_lints/src/future_not_send.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs index 0a02aa7533c17..17dd3cd5493e7 100644 --- a/clippy_lints/src/future_not_send.rs +++ b/clippy_lints/src/future_not_send.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FutureNotSend { let trait_ref = trait_pred.to_poly_trait_ref(); db.note(&*format!( "`{}` doesn't implement `{}`", - trait_ref.self_ty(), + trait_ref.skip_binder().self_ty(), trait_ref.print_only_trait_path(), )); } From 56f87efa2c587539ea1e7f22e2feff5107429aae Mon Sep 17 00:00:00 2001 From: Camelid <37223377+camelid@users.noreply.github.com> Date: Mon, 1 Jun 2020 13:01:01 -0700 Subject: [PATCH 559/695] Include kind in `bug!` Co-authored-by: hafiz <20735482+ayazhafiz@users.noreply.github.com> --- src/librustc_typeck/astconv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7173ed3d24ec8..f1dc7e5390629 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -491,7 +491,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "constant" => ParamKindOrd::Const, // It's more concise to match on the string representation, though it means // the match is non-exhaustive. - _ => bug!("invalid generic parameter kind"), + _ => bug!("invalid generic parameter kind {}", kind), }; let arg_ord = match arg { GenericArg::Lifetime(_) => ParamKindOrd::Lifetime, From 5fbbfbbfa9319d38d0f9acf54b3ffac67d6c3136 Mon Sep 17 00:00:00 2001 From: Julian Wollersberger <24991778+Julian-Wollersberger@users.noreply.github.com> Date: Fri, 29 May 2020 17:37:16 +0200 Subject: [PATCH 560/695] Simplify raw string error reporting. This makes `UnvalidatedRawStr` and `ValidatedRawStr` unnecessary and removes 70 lines. --- src/librustc_lexer/src/lib.rs | 150 ++++++++++---------------------- src/librustc_lexer/src/tests.rs | 100 ++++----------------- src/librustc_parse/lexer/mod.rs | 51 +++++------ 3 files changed, 85 insertions(+), 216 deletions(-) diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index c2139d07f378a..cf90c6d838635 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -29,7 +29,7 @@ mod tests; use self::LiteralKind::*; use self::TokenKind::*; use crate::cursor::{Cursor, EOF_CHAR}; -use std::convert::TryInto; +use std::convert::TryFrom; /// Parsed token. /// It doesn't contain information about data that has been parsed, @@ -142,84 +142,24 @@ pub enum LiteralKind { /// "b"abc"", "b"abc" ByteStr { terminated: bool }, /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a" - RawStr(UnvalidatedRawStr), + RawStr { n_hashes: u16, err: Option }, /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a" - RawByteStr(UnvalidatedRawStr), -} - -/// Represents something that looks like a raw string, but may have some -/// problems. Use `.validate()` to convert it into something -/// usable. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct UnvalidatedRawStr { - /// The prefix (`r###"`) is valid - valid_start: bool, - - /// The postfix (`"###`) is valid - valid_end: bool, - - /// The number of leading `#` - n_start_hashes: usize, - /// The number of trailing `#`. `n_end_hashes` <= `n_start_hashes` - n_end_hashes: usize, - /// The offset starting at `r` or `br` where the user may have intended to end the string. - /// Currently, it is the longest sequence of pattern `"#+"`. - possible_terminator_offset: Option, + RawByteStr { n_hashes: u16, err: Option }, } /// Error produced validating a raw string. Represents cases like: -/// - `r##~"abcde"##`: `LexRawStrError::InvalidStarter` -/// - `r###"abcde"##`: `LexRawStrError::NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)` -/// - Too many `#`s (>65536): `TooManyDelimiters` +/// - `r##~"abcde"##`: `InvalidStarter` +/// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)` +/// - Too many `#`s (>65535): `TooManyDelimiters` #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum LexRawStrError { +pub enum RawStrError { /// Non `#` characters exist between `r` and `"` eg. `r#~"..` - InvalidStarter, + InvalidStarter { bad_char: char }, /// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they /// may have intended to terminate it. NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option }, - /// More than 65536 `#`s exist. - TooManyDelimiters, -} - -/// Raw String that contains a valid prefix (`#+"`) and postfix (`"#+`) where -/// there are a matching number of `#` characters in both. Note that this will -/// not consume extra trailing `#` characters: `r###"abcde"####` is lexed as a -/// `ValidatedRawString { n_hashes: 3 }` followed by a `#` token. -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -pub struct ValidatedRawStr { - n_hashes: u16, -} - -impl ValidatedRawStr { - pub fn num_hashes(&self) -> u16 { - self.n_hashes - } -} - -impl UnvalidatedRawStr { - pub fn validate(self) -> Result { - if !self.valid_start { - return Err(LexRawStrError::InvalidStarter); - } - - // Only up to 65535 `#`s are allowed in raw strings - let n_start_safe: u16 = - self.n_start_hashes.try_into().map_err(|_| LexRawStrError::TooManyDelimiters)?; - - if self.n_start_hashes > self.n_end_hashes || !self.valid_end { - Err(LexRawStrError::NoTerminator { - expected: self.n_start_hashes, - found: self.n_end_hashes, - possible_terminator_offset: self.possible_terminator_offset, - }) - } else { - // Since the lexer should never produce a literal with n_end > n_start, if n_start <= n_end, - // they must be equal. - debug_assert_eq!(self.n_start_hashes, self.n_end_hashes); - Ok(ValidatedRawStr { n_hashes: n_start_safe }) - } - } + /// More than 65535 `#`s exist. + TooManyDelimiters { found: usize }, } /// Base of numeric literal encoding according to its prefix. @@ -354,12 +294,12 @@ impl Cursor<'_> { 'r' => match (self.first(), self.second()) { ('#', c1) if is_id_start(c1) => self.raw_ident(), ('#', _) | ('"', _) => { - let raw_str_i = self.raw_double_quoted_string(1); + let (n_hashes, err) = self.raw_double_quoted_string(1); let suffix_start = self.len_consumed(); - if raw_str_i.n_end_hashes == raw_str_i.n_start_hashes { + if err.is_none() { self.eat_literal_suffix(); } - let kind = RawStr(raw_str_i); + let kind = RawStr { n_hashes, err }; Literal { kind, suffix_start } } _ => self.ident(), @@ -389,14 +329,12 @@ impl Cursor<'_> { } ('r', '"') | ('r', '#') => { self.bump(); - let raw_str_i = self.raw_double_quoted_string(2); + let (n_hashes, err) = self.raw_double_quoted_string(2); let suffix_start = self.len_consumed(); - let terminated = raw_str_i.n_start_hashes == raw_str_i.n_end_hashes; - if terminated { + if err.is_none() { self.eat_literal_suffix(); } - - let kind = RawByteStr(raw_str_i); + let kind = RawByteStr { n_hashes, err }; Literal { kind, suffix_start } } _ => self.ident(), @@ -692,27 +630,34 @@ impl Cursor<'_> { false } - /// Eats the double-quoted string and returns an `UnvalidatedRawStr`. - fn raw_double_quoted_string(&mut self, prefix_len: usize) -> UnvalidatedRawStr { + /// Eats the double-quoted string and returns `n_hashes` and an error if encountered. + fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u16, Option) { + // Wrap the actual function to handle the error with too many hashes. + // This way, it eats the whole raw string. + let (n_hashes, err) = self.raw_string_unvalidated(prefix_len); + // Only up to 65535 `#`s are allowed in raw strings + match u16::try_from(n_hashes) { + Ok(num) => (num, err), + // We lie about the number of hashes here :P + Err(_) => (0, Some(RawStrError::TooManyDelimiters { found: n_hashes })), + } + } + + fn raw_string_unvalidated(&mut self, prefix_len: usize) -> (usize, Option) { debug_assert!(self.prev() == 'r'); - let mut valid_start: bool = false; let start_pos = self.len_consumed(); - let (mut possible_terminator_offset, mut max_hashes) = (None, 0); + let mut possible_terminator_offset = None; + let mut max_hashes = 0; // Count opening '#' symbols. let n_start_hashes = self.eat_while(|c| c == '#'); // Check that string is started. match self.bump() { - Some('"') => valid_start = true, - _ => { - return UnvalidatedRawStr { - valid_start, - valid_end: false, - n_start_hashes, - n_end_hashes: 0, - possible_terminator_offset, - }; + Some('"') => (), + c => { + let c = c.unwrap_or(EOF_CHAR); + return (n_start_hashes, Some(RawStrError::InvalidStarter { bad_char: c })); } } @@ -722,13 +667,14 @@ impl Cursor<'_> { self.eat_while(|c| c != '"'); if self.is_eof() { - return UnvalidatedRawStr { - valid_start, - valid_end: false, + return ( n_start_hashes, - n_end_hashes: max_hashes, - possible_terminator_offset, - }; + Some(RawStrError::NoTerminator { + expected: n_start_hashes, + found: max_hashes, + possible_terminator_offset, + }), + ); } // Eat closing double quote. @@ -737,7 +683,7 @@ impl Cursor<'_> { // Check that amount of closing '#' symbols // is equal to the amount of opening ones. // Note that this will not consume extra trailing `#` characters: - // `r###"abcde"####` is lexed as a `LexedRawString { n_hashes: 3 }` + // `r###"abcde"####` is lexed as a `RawStr { n_hashes: 3 }` // followed by a `#` token. let mut hashes_left = n_start_hashes; let is_closing_hash = |c| { @@ -751,13 +697,7 @@ impl Cursor<'_> { let n_end_hashes = self.eat_while(is_closing_hash); if n_end_hashes == n_start_hashes { - return UnvalidatedRawStr { - valid_start, - valid_end: true, - n_start_hashes, - n_end_hashes, - possible_terminator_offset: None, - }; + return (n_start_hashes, None); } else if n_end_hashes > max_hashes { // Keep track of possible terminators to give a hint about // where there might be a missing terminator diff --git a/src/librustc_lexer/src/tests.rs b/src/librustc_lexer/src/tests.rs index 725799374fc64..e6acc26ec2f34 100644 --- a/src/librustc_lexer/src/tests.rs +++ b/src/librustc_lexer/src/tests.rs @@ -2,77 +2,37 @@ mod tests { use crate::*; - fn check_raw_str( - s: &str, - expected: UnvalidatedRawStr, - validated: Result, - ) { + fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option) { let s = &format!("r{}", s); let mut cursor = Cursor::new(s); cursor.bump(); - let tok = cursor.raw_double_quoted_string(0); - assert_eq!(tok, expected); - assert_eq!(tok.validate(), validated); + let (n_hashes, err) = cursor.raw_double_quoted_string(0); + assert_eq!(n_hashes, expected_hashes); + assert_eq!(err, expected_err); } #[test] fn test_naked_raw_str() { - check_raw_str( - r#""abc""#, - UnvalidatedRawStr { - n_start_hashes: 0, - n_end_hashes: 0, - valid_start: true, - valid_end: true, - possible_terminator_offset: None, - }, - Ok(ValidatedRawStr { n_hashes: 0 }), - ); + check_raw_str(r#""abc""#, 0, None); } #[test] fn test_raw_no_start() { - check_raw_str( - r##""abc"#"##, - UnvalidatedRawStr { - n_start_hashes: 0, - n_end_hashes: 0, - valid_start: true, - valid_end: true, - possible_terminator_offset: None, - }, - Ok(ValidatedRawStr { n_hashes: 0 }), - ); + check_raw_str(r##""abc"#"##, 0, None); } #[test] fn test_too_many_terminators() { // this error is handled in the parser later - check_raw_str( - r###"#"abc"##"###, - UnvalidatedRawStr { - n_start_hashes: 1, - n_end_hashes: 1, - valid_end: true, - valid_start: true, - possible_terminator_offset: None, - }, - Ok(ValidatedRawStr { n_hashes: 1 }), - ); + check_raw_str(r###"#"abc"##"###, 1, None); } #[test] fn test_unterminated() { check_raw_str( r#"#"abc"#, - UnvalidatedRawStr { - n_start_hashes: 1, - n_end_hashes: 0, - valid_end: false, - valid_start: true, - possible_terminator_offset: None, - }, - Err(LexRawStrError::NoTerminator { + 1, + Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None, @@ -80,14 +40,8 @@ mod tests { ); check_raw_str( r###"##"abc"#"###, - UnvalidatedRawStr { - n_start_hashes: 2, - n_end_hashes: 1, - valid_start: true, - valid_end: false, - possible_terminator_offset: Some(7), - }, - Err(LexRawStrError::NoTerminator { + 2, + Some(RawStrError::NoTerminator { expected: 2, found: 1, possible_terminator_offset: Some(7), @@ -96,14 +50,8 @@ mod tests { // We're looking for "# not just any # check_raw_str( r###"##"abc#"###, - UnvalidatedRawStr { - n_start_hashes: 2, - n_end_hashes: 0, - valid_start: true, - valid_end: false, - possible_terminator_offset: None, - }, - Err(LexRawStrError::NoTerminator { + 2, + Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None, @@ -113,17 +61,7 @@ mod tests { #[test] fn test_invalid_start() { - check_raw_str( - r##"#~"abc"#"##, - UnvalidatedRawStr { - n_start_hashes: 1, - n_end_hashes: 0, - valid_start: false, - valid_end: false, - possible_terminator_offset: None, - }, - Err(LexRawStrError::InvalidStarter), - ); + check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' })); } #[test] @@ -131,14 +69,8 @@ mod tests { // https://github.com/rust-lang/rust/issues/70677 check_raw_str( r#"""#, - UnvalidatedRawStr { - n_start_hashes: 0, - n_end_hashes: 0, - valid_start: true, - valid_end: false, - possible_terminator_offset: None, - }, - Err(LexRawStrError::NoTerminator { + 0, + Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None, diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 2b7d5e5adb432..f8a5db26d3231 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -3,7 +3,7 @@ use rustc_ast::util::comments; use rustc_data_structures::sync::Lrc; use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError}; use rustc_lexer::Base; -use rustc_lexer::{unescape, LexRawStrError, UnvalidatedRawStr, ValidatedRawStr}; +use rustc_lexer::{unescape, RawStrError}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Pos, Span}; @@ -359,15 +359,13 @@ impl<'a> StringReader<'a> { } (token::ByteStr, Mode::ByteStr, 2, 1) // b" " } - rustc_lexer::LiteralKind::RawStr(unvalidated_raw_str) => { - let valid_raw_str = self.validate_and_report_errors(start, unvalidated_raw_str); - let n_hashes = valid_raw_str.num_hashes(); + rustc_lexer::LiteralKind::RawStr { n_hashes, err } => { + self.report_raw_str_error(start, err); let n = u32::from(n_hashes); (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "## } - rustc_lexer::LiteralKind::RawByteStr(unvalidated_raw_str) => { - let validated_raw_str = self.validate_and_report_errors(start, unvalidated_raw_str); - let n_hashes = validated_raw_str.num_hashes(); + rustc_lexer::LiteralKind::RawByteStr { n_hashes, err } => { + self.report_raw_str_error(start, err); let n = u32::from(n_hashes); (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "## } @@ -459,28 +457,21 @@ impl<'a> StringReader<'a> { } } - fn validate_and_report_errors( - &self, - start: BytePos, - unvalidated_raw_str: UnvalidatedRawStr, - ) -> ValidatedRawStr { - match unvalidated_raw_str.validate() { - Err(LexRawStrError::InvalidStarter) => self.report_non_started_raw_string(start), - Err(LexRawStrError::NoTerminator { expected, found, possible_terminator_offset }) => { - self.report_unterminated_raw_string( - start, - expected, - possible_terminator_offset, - found, - ) + fn report_raw_str_error(&self, start: BytePos, opt_err: Option) { + match opt_err { + Some(RawStrError::InvalidStarter { bad_char }) => { + self.report_non_started_raw_string(start, bad_char) + } + Some(RawStrError::NoTerminator { expected, found, possible_terminator_offset }) => self + .report_unterminated_raw_string(start, expected, possible_terminator_offset, found), + Some(RawStrError::TooManyDelimiters { found }) => { + self.report_too_many_hashes(start, found) } - Err(LexRawStrError::TooManyDelimiters) => self.report_too_many_hashes(start), - Ok(valid) => valid, + None => (), } } - fn report_non_started_raw_string(&self, start: BytePos) -> ! { - let bad_char = self.str_from(start).chars().last().unwrap(); + fn report_non_started_raw_string(&self, start: BytePos, bad_char: char) -> ! { self.struct_fatal_span_char( start, self.pos, @@ -530,11 +521,17 @@ impl<'a> StringReader<'a> { FatalError.raise() } - fn report_too_many_hashes(&self, start: BytePos) -> ! { + /// Note: It was decided to not add a test case, because it would be to big. + /// https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180 + fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! { self.fatal_span_( start, self.pos, - "too many `#` symbols: raw strings may be delimited by up to 65535 `#` symbols", + &format!( + "too many `#` symbols: raw strings may be delimited \ + by up to 65535 `#` symbols, but found {}", + found + ), ) .raise(); } From 7be8077b3fe7565573001b602f8709467da903e7 Mon Sep 17 00:00:00 2001 From: Julian Wollersberger <24991778+Julian-Wollersberger@users.noreply.github.com> Date: Mon, 1 Jun 2020 13:25:41 +0200 Subject: [PATCH 561/695] Cleanup: Inline `struct_span_fatal()`, which is only called once, and remove an outdated FIXME. --- src/librustc_parse/lexer/mod.rs | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index f8a5db26d3231..7e59f06e44ae3 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -49,13 +49,12 @@ impl<'a> StringReader<'a> { // Make sure external source is loaded first, before accessing it. // While this can't show up during normal parsing, `retokenize` may // be called with a source file from an external crate. - sess.source_map().ensure_source_file_source_present(source_file.clone()); + sess.source_map().ensure_source_file_source_present(Lrc::clone(&source_file)); - // FIXME(eddyb) use `Lrc` or similar to avoid cloning the `String`. let src = if let Some(src) = &source_file.src { - src.clone() + Lrc::clone(&src) } else if let Some(src) = source_file.external_src.borrow().get_source() { - src.clone() + Lrc::clone(&src) } else { sess.span_diagnostic .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); @@ -125,10 +124,7 @@ impl<'a> StringReader<'a> { debug!("try_next_token: {:?}({:?})", token.kind, self.str_from(start)); - // This could use `?`, but that makes code significantly (10-20%) slower. - // https://github.com/rust-lang/rust/issues/37939 let kind = self.cook_lexer_token(token.kind, start); - let span = self.mk_sp(start, self.pos); Token::new(kind, span) } @@ -153,15 +149,6 @@ impl<'a> StringReader<'a> { self.err_span(self.mk_sp(from_pos, to_pos), m) } - fn struct_span_fatal( - &self, - from_pos: BytePos, - to_pos: BytePos, - m: &str, - ) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), m) - } - fn struct_fatal_span_char( &self, from_pos: BytePos, @@ -380,12 +367,7 @@ impl<'a> StringReader<'a> { } rustc_lexer::LiteralKind::Float { base, empty_exponent } => { if empty_exponent { - let mut err = self.struct_span_fatal( - start, - self.pos, - "expected at least one digit in exponent", - ); - err.emit(); + self.err_span_(start, self.pos, "expected at least one digit in exponent"); } match base { @@ -475,8 +457,7 @@ impl<'a> StringReader<'a> { self.struct_fatal_span_char( start, self.pos, - "found invalid character; only `#` is allowed \ - in raw string delimitation", + "found invalid character; only `#` is allowed in raw string delimitation", bad_char, ) .emit(); From 4f30c6893700647a11db84818011603199dc248f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jun 2020 00:55:11 +0200 Subject: [PATCH 562/695] Fix comment Co-authored-by: Aaron Hill --- src/test/ui/consts/miri_unleashed/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/miri_unleashed/tls.rs b/src/test/ui/consts/miri_unleashed/tls.rs index 27cb802823525..ba86a554bbb68 100644 --- a/src/test/ui/consts/miri_unleashed/tls.rs +++ b/src/test/ui/consts/miri_unleashed/tls.rs @@ -7,7 +7,7 @@ use std::thread; #[thread_local] static A: u8 = 0; -// Make sure we catch executing inline assembly. +// Make sure we catch accessing thread-local storage. static TEST_BAD: () = { unsafe { let _val = A; } //~^ ERROR could not evaluate static initializer From 3dd6f2cd75102af36faf345e62a06a58cdaf15b9 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 1 Jun 2020 16:21:27 -0700 Subject: [PATCH 563/695] Don't count pathless --extern options for unused-crate-dependencies warnings `--extern proc_macro` is used to add the proc_macro crate to the extern prelude for all procmacros. In general pathless `--extern` only references sysroot/standard libraries and so should be exempt from unused-crate-dependencies warnings. --- src/librustc_metadata/creader.rs | 8 ++++++-- .../ui/unused-crate-deps/ignore-pathless-extern.rs | 12 ++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/unused-crate-deps/ignore-pathless-extern.rs diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index db29e9538999a..7e902f0ade2ef 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -18,7 +18,7 @@ use rustc_middle::middle::cstore::{ CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn, }; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, CrateType}; +use rustc_session::config::{self, CrateType, ExternLocation}; use rustc_session::lint; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; @@ -850,7 +850,11 @@ impl<'a> CrateLoader<'a> { // Make a point span rather than covering the whole file let span = krate.span.shrink_to_lo(); // Complain about anything left over - for (name, _) in self.sess.opts.externs.iter() { + for (name, entry) in self.sess.opts.externs.iter() { + if let ExternLocation::FoundInLibrarySearchDirectories = entry.location { + // Don't worry about pathless `--extern foo` sysroot references + continue; + } if !self.used_extern_options.contains(&Symbol::intern(name)) { self.sess.parse_sess.buffer_lint( lint::builtin::UNUSED_CRATE_DEPENDENCIES, diff --git a/src/test/ui/unused-crate-deps/ignore-pathless-extern.rs b/src/test/ui/unused-crate-deps/ignore-pathless-extern.rs new file mode 100644 index 0000000000000..8c273cb534d74 --- /dev/null +++ b/src/test/ui/unused-crate-deps/ignore-pathless-extern.rs @@ -0,0 +1,12 @@ +// Pathless --extern references don't count + +// edition:2018 +// check-pass +// aux-crate:bar=bar.rs +// compile-flags:--extern proc_macro + +#![warn(unused_crate_dependencies)] + +use bar as _; + +fn main() {} From 860b381793690247800def81e3031a4d33b7e07c Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 1 Jun 2020 17:15:23 -0700 Subject: [PATCH 564/695] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 9fcb8c1d20c17..40ebd52206e25 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 9fcb8c1d20c17f51054f7aa4e08ff28d381fe096 +Subproject commit 40ebd52206e25c7a576ee42c137cc06a745a167a From a3344d1a3aef9d8c1171899fcd34486a7038a984 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 1 Jun 2020 17:47:26 -0700 Subject: [PATCH 565/695] Add a test to ensure Fuse stays covariant --- src/test/ui/variance-iterators-in-libcore.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/ui/variance-iterators-in-libcore.rs b/src/test/ui/variance-iterators-in-libcore.rs index 2ab3a8ab5c129..a542e44d517a7 100644 --- a/src/test/ui/variance-iterators-in-libcore.rs +++ b/src/test/ui/variance-iterators-in-libcore.rs @@ -1,9 +1,10 @@ // run-pass -#![allow(warnings)] +#![allow(dead_code)] -use std::iter::Zip; +use std::iter::{Fuse, Zip}; +fn fuse_covariant<'a, I>(iter: Fuse<&'static I>) -> Fuse<&'a I> { iter } fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter } fn main() { } From 1b7ec76c16b18b01acd07f987db488a642492049 Mon Sep 17 00:00:00 2001 From: Tom Eccles Date: Thu, 28 May 2020 16:27:56 +0100 Subject: [PATCH 566/695] tools/remote-test-{server,client}: support RUST_TEST_TMPDIR Some tests (e.g. ui-fulldeps/create-dir-all-bare.rs) assume that RUST_TEST_TMPDIR exists on the system running the test. Expand remote-test-{server,client} such that a tmp directory is created on the remote runner and this environment variable will point at it. --- src/tools/remote-test-client/src/main.rs | 2 +- src/tools/remote-test-server/src/main.rs | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index 259477e9a1c36..efc29163455be 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -224,7 +224,7 @@ fn run(support_lib_count: usize, exe: String, all_args: Vec) { // by the client. for (k, v) in env::vars() { match &k[..] { - "PATH" | "LD_LIBRARY_PATH" | "PWD" => continue, + "PATH" | "LD_LIBRARY_PATH" | "PWD" | "RUST_TEST_TMPDIR" => continue, _ => {} } t!(client.write_all(k.as_bytes())); diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index e7eff35e55725..ce8e52a42f3c3 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -83,16 +83,19 @@ fn main() { }; let listener = t!(TcpListener::bind(bind_addr)); - let work: PathBuf = if cfg!(target_os = "android") { - "/data/tmp/work".into() + let (work, tmp): (PathBuf, PathBuf) = if cfg!(target_os = "android") { + ("/data/tmp/work".into(), "/data/tmp/work/tmp".into()) } else { - let mut temp_dir = env::temp_dir(); - temp_dir.push("work"); - temp_dir + let mut work_dir = env::temp_dir(); + work_dir.push("work"); + let mut tmp_dir = work_dir.clone(); + tmp_dir.push("tmp"); + (work_dir, tmp_dir) }; println!("listening!"); t!(fs::create_dir_all(&work)); + t!(fs::create_dir_all(&tmp)); let lock = Arc::new(Mutex::new(())); @@ -109,7 +112,8 @@ fn main() { } else if &buf[..] == b"run " { let lock = lock.clone(); let work = work.clone(); - thread::spawn(move || handle_run(socket, &work, &lock)); + let tmp = tmp.clone(); + thread::spawn(move || handle_run(socket, &work, &tmp, &lock)); } else { panic!("unknown command {:?}", buf); } @@ -134,7 +138,7 @@ impl Drop for RemoveOnDrop<'_> { } } -fn handle_run(socket: TcpStream, work: &Path, lock: &Mutex<()>) { +fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>) { let mut arg = Vec::new(); let mut reader = BufReader::new(socket); @@ -226,6 +230,9 @@ fn handle_run(socket: TcpStream, work: &Path, lock: &Mutex<()>) { cmd.env("LD_LIBRARY_PATH", format!("{}:{}", work.display(), path.display())); } + // Some tests assume RUST_TEST_TMPDIR exists + cmd.env("RUST_TEST_TMPDIR", tmp.to_owned()); + // Spawn the child and ferry over stdout/stderr to the socket in a framed // fashion (poor man's style) let mut child = From 9e137bb8b685785fce6d1bc870bc197634b3796e Mon Sep 17 00:00:00 2001 From: Tom Eccles Date: Thu, 28 May 2020 17:53:29 +0100 Subject: [PATCH 567/695] tools/remote-test-server: make use of verbose option There was an unused verbose command line argument. Add some prints if verbose is set. --- src/tools/remote-test-server/src/main.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index ce8e52a42f3c3..8c56910e2dfad 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -41,6 +41,7 @@ macro_rules! t { static TEST: AtomicUsize = AtomicUsize::new(0); +#[derive(Copy, Clone)] struct Config { pub remote: bool, pub verbose: bool, @@ -71,6 +72,12 @@ impl Config { } } +fn print_verbose(s: &str, conf: Config) { + if conf.verbose { + println!("{}", s); + } +} + fn main() { println!("starting test server"); @@ -92,7 +99,7 @@ fn main() { tmp_dir.push("tmp"); (work_dir, tmp_dir) }; - println!("listening!"); + println!("listening on {}!", bind_addr); t!(fs::create_dir_all(&work)); t!(fs::create_dir_all(&tmp)); @@ -106,23 +113,25 @@ fn main() { continue; } if &buf[..] == b"ping" { + print_verbose("Received ping", config); t!(socket.write_all(b"pong")); } else if &buf[..] == b"push" { - handle_push(socket, &work); + handle_push(socket, &work, config); } else if &buf[..] == b"run " { let lock = lock.clone(); let work = work.clone(); let tmp = tmp.clone(); - thread::spawn(move || handle_run(socket, &work, &tmp, &lock)); + thread::spawn(move || handle_run(socket, &work, &tmp, &lock, config)); } else { panic!("unknown command {:?}", buf); } } } -fn handle_push(socket: TcpStream, work: &Path) { +fn handle_push(socket: TcpStream, work: &Path, config: Config) { let mut reader = BufReader::new(socket); - recv(&work, &mut reader); + let dst = recv(&work, &mut reader); + print_verbose(&format!("push {:#?}", dst), config); let mut socket = reader.into_inner(); t!(socket.write_all(b"ack ")); @@ -138,7 +147,7 @@ impl Drop for RemoveOnDrop<'_> { } } -fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>) { +fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, config: Config) { let mut arg = Vec::new(); let mut reader = BufReader::new(socket); @@ -205,6 +214,7 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>) { // binary is and then we'll download it all to the exe path we calculated // earlier. let exe = recv(&path, &mut reader); + print_verbose(&format!("run {:#?}", exe), config); let mut cmd = Command::new(&exe); cmd.args(args); From 81df5ac241831ed544cecfc9ccbb7dfbe61a87fc Mon Sep 17 00:00:00 2001 From: Tom Eccles Date: Thu, 28 May 2020 17:32:12 +0100 Subject: [PATCH 568/695] compiletest: Add name directive for remote runners Allow tests to use // ignore-remote to ignore the test when using remote-test-{client,server}. In most situations this would be covered by // ignore-cross-compile but I see no reason that a non-cross compiled remote test runner shouldn't work. --- src/test/ui-fulldeps/compiler-calls.rs | 1 + src/test/ui-fulldeps/mod_dir_path_canonicalized.rs | 1 + src/tools/compiletest/src/header.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs index bd9113c7079ea..e97dcab6ae560 100644 --- a/src/test/ui-fulldeps/compiler-calls.rs +++ b/src/test/ui-fulldeps/compiler-calls.rs @@ -3,6 +3,7 @@ // ignore-cross-compile // ignore-stage1 +// ignore-remote #![feature(rustc_private)] diff --git a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs index 3c5738f574c26..ff7bbafe7c212 100644 --- a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -1,6 +1,7 @@ // run-pass // Testing that a librustc_ast can parse modules with canonicalized base path // ignore-cross-compile +// ignore-remote #![feature(rustc_private)] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index cb648db8830ef..9d1940dd4d6c2 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -853,6 +853,7 @@ impl Config { name == util::get_pointer_width(&self.target) || // pointer width name == self.stage_id.split('-').next().unwrap() || // stage (self.target != self.host && name == "cross-compile") || + (self.remote_test_client.is_some() && name == "remote") || match self.compare_mode { Some(CompareMode::Nll) => name == "compare-mode-nll", Some(CompareMode::Polonius) => name == "compare-mode-polonius", From cb2308de549975f538bc51325481ad235cea4e9d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 15:29:51 +0200 Subject: [PATCH 569/695] implement wf checking for constants --- src/librustc_trait_selection/traits/wf.rs | 125 +++++++++++++++------- 1 file changed, 87 insertions(+), 38 deletions(-) diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 39c7528a63240..60a8881521426 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -4,7 +4,7 @@ use crate::traits; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::Span; use std::rc::Rc; @@ -37,7 +37,7 @@ pub fn obligations<'a, 'tcx>( }; let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - wf.compute(ty); + wf.compute(ty.into()); debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); let result = wf.normalize(); @@ -45,6 +45,36 @@ pub fn obligations<'a, 'tcx>( Some(result) } +/// Returns the set of obligations needed to make the `constant` well-formed. +pub fn const_obligations<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + constant: &'tcx ty::Const<'tcx>, + span: Span, +) -> Option>> { + let constant = match constant.val { + ty::ConstKind::Infer(infer) => { + let resolved = infcx.shallow_resolve(infer); + if resolved == infer { + // No progress. + return None; + } + + infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ..*constant }) + } + _ => constant, + }; + + let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; + wf.compute(constant.into()); + debug!("wf::const obligations({:?}, body_id={:?}) = {:?}", constant, body_id, wf.out); + + let result = wf.normalize(); + debug!("wf::const obligations({:?}, body_id={:?}) ~~> {:?}", constant, body_id, result); + Some(result) +} + /// Returns the obligations that make this trait reference /// well-formed. For example, if there is a trait `Set` defined like /// `trait Set`, then the trait reference `Foo: Set` is WF @@ -78,33 +108,36 @@ pub fn predicate_obligations<'a, 'tcx>( } ty::PredicateKind::RegionOutlives(..) => {} ty::PredicateKind::TypeOutlives(t) => { - wf.compute(t.skip_binder().0); + wf.compute(t.skip_binder().0.into()); } ty::PredicateKind::Projection(t) => { let t = t.skip_binder(); // (*) wf.compute_projection(t.projection_ty); - wf.compute(t.ty); + wf.compute(t.ty.into()); } &ty::PredicateKind::WellFormed(t) => { - wf.compute(t); + wf.compute(t.into()); } ty::PredicateKind::ObjectSafe(_) => {} ty::PredicateKind::ClosureKind(..) => {} ty::PredicateKind::Subtype(data) => { - wf.compute(data.skip_binder().a); // (*) - wf.compute(data.skip_binder().b); // (*) + wf.compute(data.skip_binder().a.into()); // (*) + wf.compute(data.skip_binder().b.into()); // (*) } &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); - for ty in substs.types() { - wf.compute(ty); + for subst in substs.iter().copied() { + wf.compute(subst); } } ty::PredicateKind::ConstEquate(c1, c2) => { - wf.compute(c1.ty); - wf.compute(c2.ty); + wf.compute(c1.ty.into()); + wf.compute(c2.ty.into()); + } + ty::Predicate::WellFormedConst(constant) => { + wf.compute(constant.into()); } } @@ -213,7 +246,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.infcx.tcx } - fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { + fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { traits::ObligationCause::new(self.span, self.body_id, code) } @@ -300,22 +333,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } - /// Pushes the obligations required for an array length to be WF - /// into `self.out`. - fn compute_array_len(&mut self, constant: ty::Const<'tcx>) { - if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val { - assert!(promoted.is_none()); - - let obligations = self.nominal_obligations(def_id, substs); - self.out.extend(obligations); - - let predicate = - ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx()); - let cause = self.cause(traits::MiscObligation); - self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); - } - } - fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); @@ -332,8 +349,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } /// Pushes all the predicates needed to validate that `ty` is WF into `out`. - fn compute(&mut self, ty: Ty<'tcx>) { - let mut walker = ty.walk(); + fn compute(&mut self, arg: GenericArg<'tcx>) { + let mut walker = arg.walk(); let param_env = self.param_env; while let Some(arg) = walker.next() { let ty = match arg.unpack() { @@ -343,9 +360,43 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // obligations are handled by the parent (e.g. `ty::Ref`). GenericArgKind::Lifetime(_) => continue, - // FIXME(eddyb) this is wrong and needs to be replaced - // (see https://github.com/rust-lang/rust/pull/70107). - GenericArgKind::Const(_) => continue, + GenericArgKind::Const(constant) => { + match constant.val { + ty::ConstKind::Unevaluated(def_id, substs, promoted) => { + assert!(promoted.is_none()); + + let obligations = self.nominal_obligations(def_id, substs); + self.out.extend(obligations); + + let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx()); + let cause = self.cause(traits::MiscObligation); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + predicate, + )); + } + ty::ConstKind::Infer(infer) => { + let resolved = self.infcx.shallow_resolve(infer); + // the `InferConst` changed, meaning that we made progress. + if resolved != infer { + let cause = self.cause(traits::MiscObligation); + + let resolved_constant = self.infcx.tcx.mk_const(ty::Const { + val: ty::ConstKind::Infer(resolved), + ..*constant + }); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateKind::WellFormedConst(resolved_constant).to_predicate(self.tcx()), + )); + } + } + _ => (), + } + continue; + } }; match ty.kind { @@ -375,10 +426,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.require_sized(subty, traits::SliceOrArrayElem); } - ty::Array(subty, len) => { + ty::Array(subty, _) => { self.require_sized(subty, traits::SliceOrArrayElem); - // FIXME(eddyb) handle `GenericArgKind::Const` above instead. - self.compute_array_len(*len); } ty::Tuple(ref tys) => { @@ -467,7 +516,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { walker.skip_current_subtree(); // subtree handled below for upvar_ty in substs.as_closure().upvar_tys() { // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(upvar_ty); + self.compute(upvar_ty.into()); } } @@ -540,7 +589,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } else { // Yes, resolved, proceed with the result. // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(ty); + self.compute(ty.into()); } } } From 81831e124e002188d95d690ea090067b3653055f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 18:28:50 +0200 Subject: [PATCH 570/695] add WellFormedConst predicate --- src/librustc_infer/infer/outlives/mod.rs | 3 +- src/librustc_infer/traits/util.rs | 5 ++ src/librustc_lint/builtin.rs | 1 + src/librustc_middle/ty/mod.rs | 12 +++- src/librustc_middle/ty/print/pretty.rs | 3 + src/librustc_middle/ty/structural_impls.rs | 4 ++ .../transform/qualify_min_const_fn.rs | 3 +- src/librustc_trait_selection/opaque_types.rs | 3 +- .../traits/error_reporting/mod.rs | 18 +++++ .../traits/fulfill.rs | 15 +++++ .../traits/object_safety.rs | 6 +- src/librustc_trait_selection/traits/select.rs | 14 ++++ src/librustc_trait_selection/traits/wf.rs | 26 +++++--- src/librustc_traits/chalk/lowering.rs | 11 ++-- .../implied_outlives_bounds.rs | 3 +- .../normalize_erasing_regions.rs | 3 +- src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/mod.rs | 65 +++++++++++-------- .../impl_wf_check/min_specialization.rs | 3 +- src/librustc_typeck/outlives/explicit.rs | 3 +- src/librustdoc/clean/mod.rs | 3 +- .../cannot-infer-const-args.stderr | 4 +- .../ui/const-generics/issues/issue-61747.rs | 3 +- .../const-generics/issues/issue-61747.stderr | 12 +++- .../ui/const-generics/issues/issue-62220.rs | 4 +- .../const-generics/issues/issue-62220.stderr | 10 +++ .../ui/const-generics/issues/issue-66205.rs | 4 +- .../const-generics/issues/issue-66205.stderr | 11 +++- .../ui/const-generics/issues/issue-68977.rs | 40 ++++++++++++ .../const-generics/issues/issue-68977.stderr | 19 ++++++ src/test/ui/const-generics/wf-misc.rs | 16 +++++ src/test/ui/const-generics/wf-misc.stderr | 27 ++++++++ 32 files changed, 296 insertions(+), 61 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-62220.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68977.rs create mode 100644 src/test/ui/const-generics/issues/issue-68977.stderr create mode 100644 src/test/ui/const-generics/wf-misc.rs create mode 100644 src/test/ui/const-generics/wf-misc.stderr diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index fd3b38e9d67b0..ad8e44a6c1d3a 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -20,7 +20,8 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::RegionOutlives(ref data) => data .no_bound_vars() .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 8081cac0067f1..1aaa07d23cc9a 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -45,6 +45,8 @@ pub fn anonymize_predicate<'tcx>( } ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2), + + ty::PredicateKind::WellFormedConst(ct) => ty::PredicateKind::WellFormedConst(ct), }; if new != *kind { new.to_predicate(tcx) } else { pred } @@ -204,6 +206,9 @@ impl Elaborator<'tcx> { // Currently, we do not elaborate const-equate // predicates. } + ty::PredicateKind::WellFormedConst(..) => { + // Currently, we do not elaborate WF predicates. + } ty::PredicateKind::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e17e8b7b9640e..bde761b01c3a0 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1218,6 +1218,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { Projection(..) | // Ignore bounds that a user can't type WellFormed(..) | + WellFormedConst(..) | ObjectSafe(..) | ClosureKind(..) | Subtype(..) | diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 4cd3be932def0..554553dc6b4cf 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1079,6 +1079,9 @@ pub enum PredicateKind<'tcx> { /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), + + /// Constant must be well formed. + WellFormedConst(&'tcx Const<'tcx>), } /// The crate outlives map is computed during typeck and contains the @@ -1195,6 +1198,9 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::ConstEquate(c1, c2) => { PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) } + PredicateKind::WellFormedConst(c) => { + PredicateKind::WellFormedConst(c.subst(tcx, substs)) + } }; if new != *kind { new.to_predicate(tcx) } else { self } @@ -1386,7 +1392,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ClosureKind(..) | PredicateKind::TypeOutlives(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) => None, + | PredicateKind::ConstEquate(..) + | PredicateKind::WellFormedConst(..) => None, } } @@ -1401,7 +1408,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) => None, + | PredicateKind::ConstEquate(..) + | PredicateKind::WellFormedConst(..) => None, } } } diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 6a11e775c8c5a..6eb11b0c9429a 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2054,6 +2054,9 @@ define_print_and_forward_display! { print(c2), write("`")) } + ty::PredicateKind::WellFormedConst(c) => { + p!(print(c), write(" well-formed")) + } } } diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index c6ecb08615fcf..19a2e89ca4177 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -247,6 +247,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), + ty::PredicateKind::WellFormedConst(c) => write!(f, "WellFormedConst({:?})", c), } } } @@ -507,6 +508,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { ty::PredicateKind::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) } + ty::PredicateKind::WellFormedConst(c) => { + tcx.lift(&c).map(ty::PredicateKind::WellFormedConst) + } } } } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 5615aa84eecd7..22959c6a3df2b 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -29,7 +29,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::Projection(_) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => continue, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => continue, ty::PredicateKind::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index f78a6207a3ab5..8bbcfb1ade58a 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1277,7 +1277,8 @@ crate fn required_region_bounds( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f8b33b782c017..1134cafbae430 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -610,6 +610,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + ty::PredicateKind::WellFormedConst(ct) => { + // Const WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + span_bug!(span, "const WF predicate not satisfied for {:?}", ct); + } + ty::PredicateKind::ConstEvaluatable(..) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, @@ -1540,6 +1549,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) } + ty::PredicateKind::WellFormedConst(ct) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if ct.references_error() || self.tcx.sess.has_errors() { + return; + } + self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) + } + ty::PredicateKind::Subtype(ref data) => { if data.references_error() || self.tcx.sess.has_errors() { // no need to overload user in such cases diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index c1d9b0a2d88e6..8ab81246e7d93 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -476,6 +476,21 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } + ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( + self.selcx.infcx(), + obligation.param_env, + obligation.cause.body_id, + constant, + obligation.cause.span, + ) { + Some(predicates) => ProcessResult::Changed(mk_pending(predicates)), + None => { + pending_obligation.stalled_on = + vec![TyOrConstInferVar::maybe_from_const(constant).unwrap()]; + ProcessResult::Unchanged + } + }, + &ty::PredicateKind::Subtype(subtype) => { match self.selcx.infcx().subtype_predicate( &obligation.cause, diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 5befc797a517a..ee7aa6b165d62 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -283,7 +283,8 @@ fn predicates_reference_self( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, } }) .collect() @@ -318,7 +319,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => false, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => false, } }) } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 7aa5aa2dae89b..9dd0592c45fbb 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -450,6 +450,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => Ok(EvaluatedToAmbig), }, + ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + constant, + obligation.cause.span, + ) { + Some(mut obligations) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) + } + None => Ok(EvaluatedToAmbig), + }, + ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::RegionOutlives(..) => { // We do not consider region relationships when evaluating trait matches. Ok(EvaluatedToOkModuloRegions) diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 60a8881521426..458a6f5b88f22 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -128,15 +128,15 @@ pub fn predicate_obligations<'a, 'tcx>( let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); - for subst in substs.iter().copied() { + for subst in substs.iter() { wf.compute(subst); } } - ty::PredicateKind::ConstEquate(c1, c2) => { - wf.compute(c1.ty.into()); - wf.compute(c2.ty.into()); + &ty::PredicateKind::ConstEquate(c1, c2) => { + wf.compute(c1.into()); + wf.compute(c2.into()); } - ty::Predicate::WellFormedConst(constant) => { + &ty::PredicateKind::WellFormedConst(constant) => { wf.compute(constant.into()); } } @@ -368,7 +368,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx()); + let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs) + .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::new( cause, @@ -389,11 +390,20 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormedConst(resolved_constant).to_predicate(self.tcx()), + ty::PredicateKind::WellFormedConst(resolved_constant) + .to_predicate(self.tcx()), )); } } - _ => (), + ty::ConstKind::Error + | ty::ConstKind::Param(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Placeholder(..) => { + // These variants are trivially WF, so nothing to do here. + } + ty::ConstKind::Value(..) => { + // FIXME: Enforce that values are structually-matchable. + } } continue; } diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index a33ada2fb6ef1..b624598322a07 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -77,7 +77,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment chalk_ir::InEnvironment>> { let clauses = self.environment.into_iter().filter_map(|clause| match clause { ChalkEnvironmentClause::Predicate(predicate) => { - match &predicate.kind() { + match predicate.kind() { ty::PredicateKind::Trait(predicate, _) => { let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, predicate); @@ -126,7 +126,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => { bug!("unexpected predicate {}", predicate) } } @@ -193,7 +194,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => { + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } } @@ -460,7 +462,8 @@ impl<'tcx> LowerInto<'tcx, Option bug!("unexpected predicate {}", &self), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => bug!("unexpected predicate {}", &self), } } } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 5dee71a2338cc..073dfe4d5920e 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -101,7 +101,8 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => vec![], + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => vec![], ty::PredicateKind::WellFormed(subty) => { wf_types.push(subty); diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index fcb75142269df..6a8d81085c575 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => true, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => true, } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 91562d576ea80..c17b3d78125cc 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -814,7 +814,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8fa65a135ac2..374ba1c73141b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3353,28 +3353,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); - - // HACK(eddyb) emulate what a `WellFormedConst` obligation would do. - // This code should be replaced with the proper WF handling ASAP. - if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val { - assert!(promoted.is_none()); - - // HACK(eddyb) let's hope these are always empty. - // let obligations = self.nominal_obligations(def_id, substs); - // self.out.extend(obligations); - - let cause = traits::ObligationCause::new( - self.tcx.def_span(const_def_id.to_def_id()), - self.body_id, - traits::MiscObligation, - ); - self.register_predicate(traits::Obligation::new( - cause, - self.param_env, - ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx), - )); - } - + self.register_wf_const_obligation( + c, + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); c } @@ -3424,11 +3407,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - /// Registers obligations that all types appearing in `substs` are well-formed. + /// Registers an obligation for checking later, during regionck, that the type `ty` must + /// outlive the region `r`. + pub fn register_wf_const_obligation( + &self, + ct: &'tcx ty::Const<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + // WF obligations never themselves fail, so no real need to give a detailed cause: + let cause = traits::ObligationCause::new(span, self.body_id, code); + self.register_predicate(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateKind::WellFormedConst(ct).to_predicate(self.tcx), + )); + } + + /// Registers obligations that all `substs` are well-formed. pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for ty in substs.types() { - if !ty.references_error() { - self.register_wf_obligation(ty, expr.span, traits::MiscObligation); + for subst in substs { + match subst.unpack() { + GenericArgKind::Lifetime(..) => { + // Nothing to do for lifetimes. + } + GenericArgKind::Type(ty) => { + if !ty.references_error() { + self.register_wf_obligation(ty, expr.span, traits::MiscObligation); + } + } + GenericArgKind::Const(ct) => { + if !ct.references_error() { + self.register_wf_const_obligation(ct, expr.span, traits::MiscObligation); + } + } } } } @@ -3860,6 +3872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::RegionOutlives(..) => None, ty::PredicateKind::TypeOutlives(..) => None, ty::PredicateKind::WellFormed(..) => None, + ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::ObjectSafe(..) => None, ty::PredicateKind::ConstEvaluatable(..) => None, ty::PredicateKind::ConstEquate(..) => None, diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index bf9a4d1cb6ca9..b2e8716b0380d 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 5740cc224cc57..cf8be687f6028 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -59,7 +59,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => (), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 371df7444b004..5c2d6c6453dbf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -491,7 +491,8 @@ impl<'a> Clean> for ty::Predicate<'a> { | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => panic!("not user writable"), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => panic!("not user writable"), } } } diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr index 6696b025855a8..b29d27e524751 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.stderr +++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr @@ -11,7 +11,9 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:9:5 | LL | foo(); - | ^^^ cannot infer type for fn item `fn() -> usize {foo::<{_: usize}>}` + | ^^^ + | + = note: unable to infer the value of a const parameter error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs index 9e0572d3568cb..cc671163e85a1 100644 --- a/src/test/ui/const-generics/issues/issue-61747.rs +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete @@ -7,6 +5,7 @@ struct Const; impl Const<{C}> { fn successor() -> Const<{C + 1}> { + //~^ ERROR constant expression depends on a generic parameter Const } } diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr index 2e405370dc0df..2685d9fdf167c 100644 --- a/src/test/ui/const-generics/issues/issue-61747.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.stderr @@ -1,5 +1,5 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61747.rs:3:12 + --> $DIR/issue-61747.rs:1:12 | LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ @@ -7,5 +7,13 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -warning: 1 warning emitted +error: constant expression depends on a generic parameter + --> $DIR/issue-61747.rs:7:23 + | +LL | fn successor() -> Const<{C + 1}> { + | ^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index c95b306320175..5c4a0d31a895d 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -1,7 +1,6 @@ -// build-pass #![allow(incomplete_features)] - #![feature(const_generics)] + pub struct Vector([T; N]); pub type TruncatedVector = Vector; @@ -9,6 +8,7 @@ pub type TruncatedVector = Vector; impl Vector { /// Drop the last component and return the vector with one fewer dimension. pub fn trunc(self) -> (TruncatedVector, T) { + //~^ ERROR constant expression depends on a generic parameter unimplemented!() } } diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.stderr new file mode 100644 index 0000000000000..d91d2bb326fc5 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62220.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-62220.rs:10:27 + | +LL | pub fn trunc(self) -> (TruncatedVector, T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 76bde1815be18..7cedf51ca0404 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -1,6 +1,6 @@ -#![allow(incomplete_features, dead_code, unconditional_recursion)] +#![allow(dead_code, unconditional_recursion)] #![feature(const_generics)] -#![feature(lazy_normalization_consts)] +//~^ WARN the feature `const_generics` is incomplete fn fact() { fact::<{ N - 1 }>(); diff --git a/src/test/ui/const-generics/issues/issue-66205.stderr b/src/test/ui/const-generics/issues/issue-66205.stderr index 416b675b56d28..1e9c0f2f3d9eb 100644 --- a/src/test/ui/const-generics/issues/issue-66205.stderr +++ b/src/test/ui/const-generics/issues/issue-66205.stderr @@ -1,3 +1,12 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-66205.rs:2:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + error: constant expression depends on a generic parameter --> $DIR/issue-66205.rs:6:12 | @@ -6,5 +15,5 @@ LL | fact::<{ N - 1 }>(); | = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs new file mode 100644 index 0000000000000..346ea3c204244 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.rs @@ -0,0 +1,40 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +struct PhantomU8; + +trait FxpStorage { + type SInt; // Add arithmetic traits as needed. +} + +macro_rules! fxp_storage_impls { + ($($($n:literal)|+ => $sint:ty),* $(,)?) => { + $($(impl FxpStorage for PhantomU8<$n> { + type SInt = $sint; + })*)* + } +} + +fxp_storage_impls! { + 1 => i8, + 2 => i16, + 3 | 4 => i32, + 5 | 6 | 7 | 8 => i64, + 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 => i128, +} + +type FxpStorageHelper = + PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + +struct Fxp +where + FxpStorageHelper: FxpStorage, + //~^ ERROR constant expression depends on a generic parameter +{ + storage: as FxpStorage>::SInt, +} + +fn main() { + Fxp::<1, 15> { storage: 0i16 }; + Fxp::<2, 15> { storage: 0i32 }; +} diff --git a/src/test/ui/const-generics/issues/issue-68977.stderr b/src/test/ui/const-generics/issues/issue-68977.stderr new file mode 100644 index 0000000000000..e1190d9026da9 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68977.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/issue-68977.rs:31:44 + | +LL | FxpStorageHelper: FxpStorage, + | ^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs new file mode 100644 index 0000000000000..4ff1b9e2da5b2 --- /dev/null +++ b/src/test/ui/const-generics/wf-misc.rs @@ -0,0 +1,16 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +pub fn arr_len() { + let _: [u8; N + 1]; + //~^ ERROR constant expression depends on a generic parameter +} + +struct Const; + +pub fn func_call() { + let _: Const::<{N + 1}>; + //~^ ERROR constant expression depends on a generic parameter +} + +fn main() {} diff --git a/src/test/ui/const-generics/wf-misc.stderr b/src/test/ui/const-generics/wf-misc.stderr new file mode 100644 index 0000000000000..03f2bf3f52699 --- /dev/null +++ b/src/test/ui/const-generics/wf-misc.stderr @@ -0,0 +1,27 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/wf-misc.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/wf-misc.rs:5:12 + | +LL | let _: [u8; N + 1]; + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/wf-misc.rs:12:12 + | +LL | let _: Const::<{N + 1}>; + | ^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors; 1 warning emitted + From ef4d2c10430c941619ccc517e709f093a4ea9689 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 26 May 2020 23:12:01 +0200 Subject: [PATCH 571/695] change WellFormed predicate to GenericArg --- src/librustc_infer/infer/combine.rs | 2 +- src/librustc_infer/infer/outlives/mod.rs | 3 +- src/librustc_infer/traits/util.rs | 5 - src/librustc_lint/builtin.rs | 1 - src/librustc_middle/ty/mod.rs | 16 +-- src/librustc_middle/ty/print/pretty.rs | 5 +- src/librustc_middle/ty/structural_impls.rs | 6 +- .../borrow_check/type_check/mod.rs | 6 +- .../transform/qualify_min_const_fn.rs | 3 +- src/librustc_trait_selection/opaque_types.rs | 3 +- .../traits/error_reporting/mod.rs | 32 ++--- .../traits/fulfill.rs | 21 +--- .../traits/object_safety.rs | 6 +- src/librustc_trait_selection/traits/select.rs | 18 +-- src/librustc_trait_selection/traits/wf.rs | 118 +++++++++--------- src/librustc_traits/chalk/lowering.rs | 48 +++---- .../implied_outlives_bounds.rs | 15 ++- .../normalize_erasing_regions.rs | 3 +- src/librustc_traits/type_op.rs | 4 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/mod.rs | 57 ++------- src/librustc_typeck/check/wfcheck.rs | 18 +-- .../impl_wf_check/min_specialization.rs | 7 +- src/librustc_typeck/outlives/explicit.rs | 3 +- src/librustdoc/clean/mod.rs | 3 +- 28 files changed, 157 insertions(+), 255 deletions(-) diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 70a2122a9ea5d..4ef4ed47cb11a 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -307,7 +307,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - ty::PredicateKind::WellFormed(b_ty).to_predicate(self.infcx.tcx), + ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx), )); } diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index ad8e44a6c1d3a..fd3b38e9d67b0 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -20,8 +20,7 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, ty::PredicateKind::RegionOutlives(ref data) => data .no_bound_vars() .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 1aaa07d23cc9a..8081cac0067f1 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -45,8 +45,6 @@ pub fn anonymize_predicate<'tcx>( } ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2), - - ty::PredicateKind::WellFormedConst(ct) => ty::PredicateKind::WellFormedConst(ct), }; if new != *kind { new.to_predicate(tcx) } else { pred } @@ -206,9 +204,6 @@ impl Elaborator<'tcx> { // Currently, we do not elaborate const-equate // predicates. } - ty::PredicateKind::WellFormedConst(..) => { - // Currently, we do not elaborate WF predicates. - } ty::PredicateKind::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index bde761b01c3a0..e17e8b7b9640e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1218,7 +1218,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { Projection(..) | // Ignore bounds that a user can't type WellFormed(..) | - WellFormedConst(..) | ObjectSafe(..) | ClosureKind(..) | Subtype(..) | diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 554553dc6b4cf..a34cff06bc1cd 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -14,7 +14,7 @@ use crate::mir::Body; use crate::mir::GeneratorLayout; use crate::traits::{self, Reveal}; use crate::ty; -use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; use rustc_ast::ast; use rustc_attr as attr; @@ -1061,7 +1061,7 @@ pub enum PredicateKind<'tcx> { Projection(PolyProjectionPredicate<'tcx>), /// No syntax: `T` well-formed. - WellFormed(Ty<'tcx>), + WellFormed(GenericArg<'tcx>), /// Trait must be object-safe. ObjectSafe(DefId), @@ -1079,9 +1079,6 @@ pub enum PredicateKind<'tcx> { /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), - - /// Constant must be well formed. - WellFormedConst(&'tcx Const<'tcx>), } /// The crate outlives map is computed during typeck and contains the @@ -1198,9 +1195,6 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::ConstEquate(c1, c2) => { PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) } - PredicateKind::WellFormedConst(c) => { - PredicateKind::WellFormedConst(c.subst(tcx, substs)) - } }; if new != *kind { new.to_predicate(tcx) } else { self } @@ -1392,8 +1386,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ClosureKind(..) | PredicateKind::TypeOutlives(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) - | PredicateKind::WellFormedConst(..) => None, + | PredicateKind::ConstEquate(..) => None, } } @@ -1408,8 +1401,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) - | PredicateKind::WellFormedConst(..) => None, + | PredicateKind::ConstEquate(..) => None, } } } diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 6eb11b0c9429a..90fb198161793 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2031,7 +2031,7 @@ define_print_and_forward_display! { ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)), ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)), ty::PredicateKind::Projection(predicate) => p!(print(predicate)), - ty::PredicateKind::WellFormed(ty) => p!(print(ty), write(" well-formed")), + ty::PredicateKind::WellFormed(arg) => p!(print(arg), write(" well-formed")), &ty::PredicateKind::ObjectSafe(trait_def_id) => { p!(write("the trait `"), print_def_path(trait_def_id, &[]), @@ -2054,9 +2054,6 @@ define_print_and_forward_display! { print(c2), write("`")) } - ty::PredicateKind::WellFormedConst(c) => { - p!(print(c), write(" well-formed")) - } } } diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index 19a2e89ca4177..6c1a524b7fee5 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -236,7 +236,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f), ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f), ty::PredicateKind::Projection(ref pair) => pair.fmt(f), - ty::PredicateKind::WellFormed(ty) => write!(f, "WellFormed({:?})", ty), + ty::PredicateKind::WellFormed(data) => write!(f, "WellFormed({:?})", data), ty::PredicateKind::ObjectSafe(trait_def_id) => { write!(f, "ObjectSafe({:?})", trait_def_id) } @@ -247,7 +247,6 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), - ty::PredicateKind::WellFormedConst(c) => write!(f, "WellFormedConst({:?})", c), } } } @@ -508,9 +507,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { ty::PredicateKind::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) } - ty::PredicateKind::WellFormedConst(c) => { - tcx.lift(&c).map(ty::PredicateKind::WellFormedConst) - } } } } diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index fdc3b291ba44a..377a0b6f25cab 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1016,7 +1016,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.prove_predicate( - ty::PredicateKind::WellFormed(inferred_ty).to_predicate(self.tcx()), + ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()), Locations::All(span), ConstraintCategory::TypeAnnotation, ); @@ -1268,7 +1268,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { obligations.obligations.push(traits::Obligation::new( ObligationCause::dummy(), param_env, - ty::PredicateKind::WellFormed(revealed_ty).to_predicate(infcx.tcx), + ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx), )); obligations.add( infcx @@ -1612,7 +1612,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_call_dest(body, term, &sig, destination, term_location); self.prove_predicates( - sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty)), + sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())), term_location.to_locations(), ConstraintCategory::Boring, ); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 22959c6a3df2b..5615aa84eecd7 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -29,8 +29,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::Projection(_) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => continue, + | ty::PredicateKind::ConstEquate(..) => continue, ty::PredicateKind::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 8bbcfb1ade58a..f78a6207a3ab5 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1277,8 +1277,7 @@ crate fn required_region_bounds( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, ty::PredicateKind::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 1134cafbae430..41811bf44b1af 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -19,6 +19,7 @@ use rustc_hir::Node; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{ self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -610,15 +611,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - ty::PredicateKind::WellFormedConst(ct) => { - // Const WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - span_bug!(span, "const WF predicate not satisfied for {:?}", ct); - } - ty::PredicateKind::ConstEvaluatable(..) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, @@ -1540,22 +1532,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { err } - ty::PredicateKind::WellFormed(ty) => { + ty::PredicateKind::WellFormed(arg) => { // Same hacky approach as above to avoid deluging user // with error messages. - if ty.references_error() || self.tcx.sess.has_errors() { + if arg.references_error() || self.tcx.sess.has_errors() { return; } - self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) - } - ty::PredicateKind::WellFormedConst(ct) => { - // Same hacky approach as above to avoid deluging user - // with error messages. - if ct.references_error() || self.tcx.sess.has_errors() { - return; + match arg.unpack() { + GenericArgKind::Lifetime(lt) => { + span_bug!(span, "unexpected well formed predicate: {:?}", lt) + } + GenericArgKind::Type(ty) => { + self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) + } + GenericArgKind::Const(ct) => { + self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) + } } - self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) } ty::PredicateKind::Subtype(ref data) => { diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 8ab81246e7d93..51c62dbb88c84 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -459,38 +459,23 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - &ty::PredicateKind::WellFormed(ty) => { + &ty::PredicateKind::WellFormed(arg) => { match wf::obligations( self.selcx.infcx(), obligation.param_env, obligation.cause.body_id, - ty, + arg, obligation.cause.span, ) { None => { pending_obligation.stalled_on = - vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()]; + vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()]; ProcessResult::Unchanged } Some(os) => ProcessResult::Changed(mk_pending(os)), } } - ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( - self.selcx.infcx(), - obligation.param_env, - obligation.cause.body_id, - constant, - obligation.cause.span, - ) { - Some(predicates) => ProcessResult::Changed(mk_pending(predicates)), - None => { - pending_obligation.stalled_on = - vec![TyOrConstInferVar::maybe_from_const(constant).unwrap()]; - ProcessResult::Unchanged - } - }, - &ty::PredicateKind::Subtype(subtype) => { match self.selcx.infcx().subtype_predicate( &obligation.cause, diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index ee7aa6b165d62..5befc797a517a 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -283,8 +283,7 @@ fn predicates_reference_self( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, } }) .collect() @@ -319,8 +318,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => false, + | ty::PredicateKind::ConstEquate(..) => false, } }) } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 9dd0592c45fbb..517433b90ee12 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -436,25 +436,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - &ty::PredicateKind::WellFormed(ty) => match wf::obligations( + &ty::PredicateKind::WellFormed(arg) => match wf::obligations( self.infcx, obligation.param_env, obligation.cause.body_id, - ty, - obligation.cause.span, - ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) - } - None => Ok(EvaluatedToAmbig), - }, - - ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - constant, + arg, obligation.cause.span, ) { Some(mut obligations) => { diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 458a6f5b88f22..dde50a849527d 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -9,9 +9,9 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstnes use rustc_span::Span; use std::rc::Rc; -/// Returns the set of obligations needed to make `ty` well-formed. -/// If `ty` contains unresolved inference variables, this may include -/// further WF obligations. However, if `ty` IS an unresolved +/// Returns the set of obligations needed to make `arg` well-formed. +/// If `arg` contains unresolved inference variables, this may include +/// further WF obligations. However, if `arg` IS an unresolved /// inference variable, returns `None`, because we are not able to /// make any progress at all. This is to prevent "livelock" where we /// say "$0 is WF if $0 is WF". @@ -19,59 +19,51 @@ pub fn obligations<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, - ty: Ty<'tcx>, + arg: GenericArg<'tcx>, span: Span, ) -> Option>> { // Handle the "livelock" case (see comment above) by bailing out if necessary. - let ty = match ty.kind { - ty::Infer(ty::TyVar(_)) => { - let resolved_ty = infcx.shallow_resolve(ty); - if resolved_ty == ty { - // No progress, bail out to prevent "livelock". - return None; - } + let arg = match arg.unpack() { + GenericArgKind::Type(ty) => { + match ty.kind { + ty::Infer(ty::TyVar(_)) => { + let resolved_ty = infcx.shallow_resolve(ty); + if resolved_ty == ty { + // No progress, bail out to prevent "livelock". + return None; + } - resolved_ty + resolved_ty + } + _ => ty, + } + .into() } - _ => ty, - }; - - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - wf.compute(ty.into()); - debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); - - let result = wf.normalize(); - debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); - Some(result) -} + GenericArgKind::Const(ct) => { + match ct.val { + ty::ConstKind::Infer(infer) => { + let resolved = infcx.shallow_resolve(infer); + if resolved == infer { + // No progress. + return None; + } -/// Returns the set of obligations needed to make the `constant` well-formed. -pub fn const_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - constant: &'tcx ty::Const<'tcx>, - span: Span, -) -> Option>> { - let constant = match constant.val { - ty::ConstKind::Infer(infer) => { - let resolved = infcx.shallow_resolve(infer); - if resolved == infer { - // No progress. - return None; + infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ty: ct.ty }) + } + _ => ct, } - - infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ..*constant }) + .into() } - _ => constant, + // There is nothing we have to do for lifetimes. + GenericArgKind::Lifetime(..) => return Some(Vec::new()), }; let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - wf.compute(constant.into()); - debug!("wf::const obligations({:?}, body_id={:?}) = {:?}", constant, body_id, wf.out); + wf.compute(arg); + debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); let result = wf.normalize(); - debug!("wf::const obligations({:?}, body_id={:?}) ~~> {:?}", constant, body_id, result); + debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result); Some(result) } @@ -115,8 +107,8 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute_projection(t.projection_ty); wf.compute(t.ty.into()); } - &ty::PredicateKind::WellFormed(t) => { - wf.compute(t.into()); + &ty::PredicateKind::WellFormed(arg) => { + wf.compute(arg); } ty::PredicateKind::ObjectSafe(_) => {} ty::PredicateKind::ClosureKind(..) => {} @@ -128,17 +120,14 @@ pub fn predicate_obligations<'a, 'tcx>( let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); - for subst in substs.iter() { - wf.compute(subst); + for arg in substs.iter() { + wf.compute(arg); } } &ty::PredicateKind::ConstEquate(c1, c2) => { wf.compute(c1.into()); wf.compute(c2.into()); } - &ty::PredicateKind::WellFormedConst(constant) => { - wf.compute(constant.into()); - } } wf.normalize() @@ -306,15 +295,22 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } let tcx = self.tcx(); - self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map( - |ty| { - traits::Obligation::new( - cause.clone(), - param_env, - ty::PredicateKind::WellFormed(ty).to_predicate(tcx), - ) - }, - )); + self.out.extend( + trait_ref + .substs + .iter() + .filter(|arg| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) + .filter(|arg| !arg.has_escaping_bound_vars()) + .map(|arg| { + traits::Obligation::new( + cause.clone(), + param_env, + ty::PredicateKind::WellFormed(arg).to_predicate(tcx), + ) + }), + ); } /// Pushes the obligations required for `trait_ref::Item` to be WF @@ -390,7 +386,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormedConst(resolved_constant) + ty::PredicateKind::WellFormed(resolved_constant.into()) .to_predicate(self.tcx()), )); } @@ -594,7 +590,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, param_env, - ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx()), + ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()), )); } else { // Yes, resolved, proceed with the result. diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index b624598322a07..9530b07e47cdb 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -36,7 +36,7 @@ use rustc_middle::traits::{ ChalkRustInterner as RustInterner, }; use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::subst::{GenericArg, SubstsRef}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable, TypeVisitor, }; @@ -126,8 +126,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { + | ty::PredicateKind::ConstEquate(..) => { bug!("unexpected predicate {}", predicate) } } @@ -166,24 +165,31 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } ty::PredicateKind::Projection(predicate) => predicate.lower_into(interner), - ty::PredicateKind::WellFormed(ty) => match ty.kind { - // These types are always WF. - ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) - } + ty::PredicateKind::WellFormed(arg) => match arg.unpack() { + GenericArgKind::Type(ty) => match ty.kind { + // These types are always WF. + ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => { + chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + } - // FIXME(chalk): Well-formed only if ref lifetime outlives type - ty::Ref(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), + // FIXME(chalk): Well-formed only if ref lifetime outlives type + ty::Ref(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), - ty::Param(..) => panic!("No Params expected."), + ty::Param(..) => panic!("No Params expected."), - // FIXME(chalk) -- ultimately I think this is what we - // want to do, and we just have rules for how to prove - // `WellFormed` for everything above, instead of - // inlining a bit the rules of the proof here. - _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( - chalk_ir::WellFormed::Ty(ty.lower_into(interner)), - )), + // FIXME(chalk) -- ultimately I think this is what we + // want to do, and we just have rules for how to prove + // `WellFormed` for everything above, instead of + // inlining a bit the rules of the proof here. + _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( + chalk_ir::WellFormed::Ty(ty.lower_into(interner)), + )), + }, + // FIXME(chalk): handle well formed consts + GenericArgKind::Const(..) => { + chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + } + GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt), }, // FIXME(chalk): other predicates @@ -194,8 +200,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => { + | ty::PredicateKind::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } } @@ -462,8 +467,7 @@ impl<'tcx> LowerInto<'tcx, Option bug!("unexpected predicate {}", &self), + | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", &self), } } } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 073dfe4d5920e..651596d0379bb 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -47,14 +47,14 @@ fn compute_implied_outlives_bounds<'tcx>( // process it next. Currently (at least) these resulting // predicates are always guaranteed to be a subset of the original // type, so we need not fear non-termination. - let mut wf_types = vec![ty]; + let mut wf_args = vec![ty.into()]; let mut implied_bounds = vec![]; let mut fulfill_cx = FulfillmentContext::new(); - while let Some(ty) = wf_types.pop() { - // Compute the obligations for `ty` to be well-formed. If `ty` is + while let Some(arg) = wf_args.pop() { + // Compute the obligations for `arg` to be well-formed. If `arg` is // an unresolved inference variable, just substituted an empty set // -- because the return type here is going to be things we *add* // to the environment, it's always ok for this set to be smaller @@ -62,7 +62,7 @@ fn compute_implied_outlives_bounds<'tcx>( // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) let obligations = - wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, ty, DUMMY_SP).unwrap_or(vec![]); + wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, arg, DUMMY_SP).unwrap_or(vec![]); // N.B., all of these predicates *ought* to be easily proven // true. In fact, their correctness is (mostly) implied by @@ -101,11 +101,10 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => vec![], + | ty::PredicateKind::ConstEquate(..) => vec![], - ty::PredicateKind::WellFormed(subty) => { - wf_types.push(subty); + &ty::PredicateKind::WellFormed(arg) => { + wf_args.push(arg); vec![] } diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index 6a8d81085c575..fcb75142269df 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -49,7 +49,6 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => true, + | ty::PredicateKind::ConstEquate(..) => true, } } diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 22077b49c3b77..374ef3fc9c783 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -140,7 +140,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { self.relate(self_ty, Variance::Invariant, impl_self_ty)?; self.prove_predicate( - ty::PredicateKind::WellFormed(impl_self_ty).to_predicate(self.tcx()), + ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()), ); } @@ -155,7 +155,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { // them? This would only be relevant if some input // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... - self.prove_predicate(ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx())); + self.prove_predicate(ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx())); Ok(()) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index f4e46a0493151..aa316105f7f11 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // we must check that return type of called functions is WF: - self.register_wf_obligation(output, call_expr.span, traits::MiscObligation); + self.register_wf_obligation(output.into(), call_expr.span, traits::MiscObligation); output } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 48d27387476a2..007794ce1b7ff 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -413,7 +413,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // the function type must also be well-formed (this is not // implied by the substs being well-formed because of inherent // impls and late-bound regions - see issue #28609). - self.register_wf_obligation(fty, self.span, traits::MiscObligation); + self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation); } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index aae02ea0273f9..ac3fa15417e9c 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(method_ty).to_predicate(tcx), + ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx), )); let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c17b3d78125cc..91562d576ea80 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -814,8 +814,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 374ba1c73141b..275581318f75d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -121,9 +121,8 @@ use rustc_middle::ty::adjustment::{ }; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{ - GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, -}; +use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts}; use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, @@ -3333,7 +3332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { let t = AstConv::ast_ty_to_ty(self, ast_t); - self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); + self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); t } @@ -3353,8 +3352,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); - self.register_wf_const_obligation( - c, + self.register_wf_obligation( + c.into(), self.tcx.hir().span(ast_c.hir_id), ObligationCauseCode::MiscObligation, ); @@ -3394,24 +3393,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// outlive the region `r`. pub fn register_wf_obligation( &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - // WF obligations never themselves fail, so no real need to give a detailed cause: - let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_predicate(traits::Obligation::new( - cause, - self.param_env, - ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx), - )); - } - - /// Registers an obligation for checking later, during regionck, that the type `ty` must - /// outlive the region `r`. - pub fn register_wf_const_obligation( - &self, - ct: &'tcx ty::Const<'tcx>, + arg: subst::GenericArg<'tcx>, span: Span, code: traits::ObligationCauseCode<'tcx>, ) { @@ -3420,28 +3402,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormedConst(ct).to_predicate(self.tcx), + ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx), )); } /// Registers obligations that all `substs` are well-formed. pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for subst in substs { - match subst.unpack() { - GenericArgKind::Lifetime(..) => { - // Nothing to do for lifetimes. - } - GenericArgKind::Type(ty) => { - if !ty.references_error() { - self.register_wf_obligation(ty, expr.span, traits::MiscObligation); - } - } - GenericArgKind::Const(ct) => { - if !ct.references_error() { - self.register_wf_const_obligation(ct, expr.span, traits::MiscObligation); - } - } - } + for arg in substs.iter().filter(|arg| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) { + self.register_wf_obligation(arg, expr.span, traits::MiscObligation); } } @@ -3872,7 +3842,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::RegionOutlives(..) => None, ty::PredicateKind::TypeOutlives(..) => None, ty::PredicateKind::WellFormed(..) => None, - ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::ObjectSafe(..) => None, ty::PredicateKind::ConstEvaluatable(..) => None, ty::PredicateKind::ConstEquate(..) => None, @@ -3914,8 +3883,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // All the input types from the fn signature must outlive the call // so as to validate implied bounds. - for (fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { - self.register_wf_obligation(fn_input_ty, arg_expr.span, traits::MiscObligation); + for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { + self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); } let expected_arg_count = fn_inputs.len(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e154184f1822c..7d9bf975c6913 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -292,7 +292,7 @@ fn check_associated_item( ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); - fcx.register_wf_obligation(ty, span, code.clone()); + fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { let sig = fcx.tcx.fn_sig(item.def_id); @@ -313,7 +313,7 @@ fn check_associated_item( if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); - fcx.register_wf_obligation(ty, span, code.clone()); + fcx.register_wf_obligation(ty.into(), span, code.clone()); } } ty::AssocKind::OpaqueTy => { @@ -406,7 +406,7 @@ fn check_type_defn<'tcx, F>( // All field types must be well-formed. for field in &variant.fields { fcx.register_wf_obligation( - field.ty, + field.ty.into(), field.span, ObligationCauseCode::MiscObligation, ) @@ -601,7 +601,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo } } - fcx.register_wf_obligation(item_ty, ty_span, ObligationCauseCode::MiscObligation); + fcx.register_wf_obligation(item_ty.into(), ty_span, ObligationCauseCode::MiscObligation); if forbid_unsized { fcx.register_bound( item_ty, @@ -650,7 +650,7 @@ fn check_impl<'tcx>( let self_ty = fcx.tcx.type_of(item_def_id); let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty); fcx.register_wf_obligation( - self_ty, + self_ty.into(), ast_self_ty.span, ObligationCauseCode::MiscObligation, ); @@ -698,7 +698,7 @@ fn check_where_clauses<'tcx, 'fcx>( // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { fcx.register_wf_obligation( - ty, + ty.into(), fcx.tcx.def_span(param.def_id), ObligationCauseCode::MiscObligation, ); @@ -841,13 +841,13 @@ fn check_fn_or_method<'fcx, 'tcx>( let sig = fcx.normalize_associated_types_in(span, &sig); let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig); - for (input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) { - fcx.register_wf_obligation(&input_ty, span, ObligationCauseCode::MiscObligation); + for (&input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) { + fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation); } implied_bounds.extend(sig.inputs()); fcx.register_wf_obligation( - sig.output(), + sig.output().into(), hir_sig.decl.output.span(), ObligationCauseCode::ReturnType, ); diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index b2e8716b0380d..e4bffedd620b9 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -332,12 +332,12 @@ fn check_predicates<'tcx>( }); // Include the well-formed predicates of the type parameters of the impl. - for ty in tcx.impl_trait_ref(impl1_def_id).unwrap().substs.types() { + for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs { if let Some(obligations) = wf::obligations( infcx, tcx.param_env(impl1_def_id), tcx.hir().as_local_hir_id(impl1_def_id), - ty, + arg, span, ) { impl2_predicates @@ -405,7 +405,6 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index cf8be687f6028..5740cc224cc57 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -59,8 +59,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => (), + | ty::PredicateKind::ConstEquate(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5c2d6c6453dbf..371df7444b004 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -491,8 +491,7 @@ impl<'a> Clean> for ty::Predicate<'a> { | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => panic!("not user writable"), + | ty::PredicateKind::ConstEquate(..) => panic!("not user writable"), } } } From 631ac9c472322077304d9acc4de21220c54c56db Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 26 May 2020 23:13:18 +0200 Subject: [PATCH 572/695] update tests --- src/librustc_trait_selection/traits/wf.rs | 7 ++++--- src/librustc_typeck/check/mod.rs | 3 +-- .../ui/const-generics/issues/issue-61935.rs | 3 +-- .../const-generics/issues/issue-61935.stderr | 12 ++++++++++-- .../lazy-normalization/issue-71922.rs | 4 ++-- .../lazy-normalization/issue-71922.stderr | 19 +++++++++++++++++++ 6 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/const-generics/lazy-normalization/issue-71922.stderr diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index dde50a849527d..5024392a0f98d 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -398,7 +398,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // These variants are trivially WF, so nothing to do here. } ty::ConstKind::Value(..) => { - // FIXME: Enforce that values are structually-matchable. + // FIXME: Enforce that values are structurally-matchable. } } continue; @@ -434,6 +434,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { ty::Array(subty, _) => { self.require_sized(subty, traits::SliceOrArrayElem); + // Note that we handle the len is implicitly checked while walking `arg`. } ty::Tuple(ref tys) => { @@ -445,11 +446,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } ty::RawPtr(_) => { - // simple cases that are WF if their type args are WF + // Simple cases that are WF if their type args are WF. } ty::Projection(data) => { - walker.skip_current_subtree(); // subtree handled by compute_projection + walker.skip_current_subtree(); // Subtree handled by compute_projection. self.compute_projection(data); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 275581318f75d..ba4bca8cd9981 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3389,8 +3389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Registers an obligation for checking later, during regionck, that the type `ty` must - /// outlive the region `r`. + /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. pub fn register_wf_obligation( &self, arg: subst::GenericArg<'tcx>, diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs index 5c987e63a9e07..0d42ff1895cdb 100644 --- a/src/test/ui/const-generics/issues/issue-61935.rs +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete @@ -8,6 +6,7 @@ trait Foo {} impl Foo for [(); N] where Self:FooImpl<{N==0}> +//~^ERROR constant expression depends on a generic parameter {} trait FooImpl{} diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr index cf0c0e24a7604..a785af5f008ea 100644 --- a/src/test/ui/const-generics/issues/issue-61935.stderr +++ b/src/test/ui/const-generics/issues/issue-61935.stderr @@ -1,5 +1,5 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61935.rs:3:12 + --> $DIR/issue-61935.rs:1:12 | LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ @@ -7,5 +7,13 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -warning: 1 warning emitted +error: constant expression depends on a generic parameter + --> $DIR/issue-61935.rs:8:14 + | +LL | Self:FooImpl<{N==0}> + | ^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs index 36513f94a9e97..0d392ddcaedcc 100644 --- a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs +++ b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs @@ -1,9 +1,9 @@ -// run-pass #![feature(const_generics)] -#![allow(incomplete_features)] +//~^ WARN the feature `const_generics` is incomplete trait Foo {} impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} +//~^ ERROR constant expression depends on a generic parameter trait FooImpl {} diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr b/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr new file mode 100644 index 0000000000000..00917571e716d --- /dev/null +++ b/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-71922.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/issue-71922.rs:5:50 + | +LL | impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted + From 786ad87d4032ed15010547ea0180d43745ff8f89 Mon Sep 17 00:00:00 2001 From: Peter Todd Date: Tue, 2 Jun 2020 09:47:33 -0400 Subject: [PATCH 573/695] Minor: off-by-one error in RELEASES.md --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 757821abcd153..fc9628bb365b4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -43,7 +43,7 @@ Libraries - [Unicode 13 is now supported.][69929] - [`String` now implements `From<&mut str>`.][69661] - [`IoSlice` now implements `Copy`.][69403] -- [`Vec` now implements `From<[T; N]>`.][68692] Where `N` is less than 32. +- [`Vec` now implements `From<[T; N]>`.][68692] Where `N` is at most 32. - [`proc_macro::LexError` now implements `fmt::Display` and `Error`.][68899] - [`from_le_bytes`, `to_le_bytes`, `from_be_bytes`, `to_be_bytes`, `from_ne_bytes`, and `to_ne_bytes` methods are now `const` for all From 503048c4d99e929f8b0af0973eba029055885b27 Mon Sep 17 00:00:00 2001 From: DutchGhost Date: Tue, 2 Jun 2020 16:12:36 +0200 Subject: [PATCH 574/695] Update README.md https://github.com/rust-lang/rust/pull/72827 changed it from `*.nix` to `Unix-like system`, but actually it should be `a Unix-like system` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b48ee8a914ec4..42fc0a63c0ffb 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ or reading the [rustc dev guide][rustcguidebuild]. [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html -### Building on Unix-like system +### Building on a Unix-like system 1. Make sure you have installed the dependencies: * `g++` 5.1 or later or `clang++` 3.5 or later From fbf0b84b32aab798258838d5e932dbc56c4a1813 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Tue, 2 Jun 2020 21:42:33 +0700 Subject: [PATCH 575/695] Make use of slice pattern --- clippy_lints/src/utils/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 6c1488664bf00..7e07e7751e34a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -165,8 +165,8 @@ pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr<'_>, path: &[&st /// Checks if an expression references a variable of the given name. pub fn match_var(expr: &Expr<'_>, var: Name) -> bool { if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { - if path.segments.len() == 1 && path.segments[0].ident.name == var { - return true; + if let [p] = path.segments { + return p.ident.name == var; } } false @@ -181,8 +181,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { match *path { - QPath::Resolved(_, ref path) if path.segments.len() == 1 => Some(&path.segments[0]), - QPath::Resolved(..) => None, + QPath::Resolved(_, ref path) => path.segments.get(0), QPath::TypeRelative(_, ref seg) => Some(seg), } } @@ -201,9 +200,12 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { QPath::Resolved(_, ref path) => match_path(path, segments), QPath::TypeRelative(ref ty, ref segment) => match ty.kind { TyKind::Path(ref inner_path) => { - !segments.is_empty() - && match_qpath(inner_path, &segments[..(segments.len() - 1)]) - && segment.ident.name.as_str() == segments[segments.len() - 1] + if let [prefix @ .., end] = segments { + if match_qpath(inner_path, prefix) { + return segment.ident.name.as_str() == *end; + } + } + false }, _ => false, }, From 47197d69ab12be03915ecaac09b80896633857dd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 2 Jun 2020 19:53:33 +0300 Subject: [PATCH 576/695] Rename directories for some compiler crates from `libx` to `librustc_x` libarena -> librustc_arena libfmt_macros -> librustc_parse_format libgraphviz -> librustc_graphviz libserialize -> librustc_serialize --- src/{libarena => librustc_arena}/Cargo.toml | 0 src/{libarena => librustc_arena}/lib.rs | 0 src/{libarena => librustc_arena}/tests.rs | 0 src/{libgraphviz => librustc_graphviz}/Cargo.toml | 0 src/{libgraphviz => librustc_graphviz}/lib.rs | 0 src/{libgraphviz => librustc_graphviz}/tests.rs | 0 src/{libfmt_macros => librustc_parse_format}/Cargo.toml | 0 src/{libfmt_macros => librustc_parse_format}/lib.rs | 0 src/{libfmt_macros => librustc_parse_format}/tests.rs | 0 src/{libserialize => librustc_serialize}/Cargo.toml | 0 src/{libserialize => librustc_serialize}/collection_impls.rs | 0 src/{libserialize => librustc_serialize}/json.rs | 0 src/{libserialize => librustc_serialize}/json/tests.rs | 0 src/{libserialize => librustc_serialize}/leb128.rs | 0 src/{libserialize => librustc_serialize}/lib.rs | 0 src/{libserialize => librustc_serialize}/opaque.rs | 0 src/{libserialize => librustc_serialize}/serialize.rs | 0 src/{libserialize => librustc_serialize}/tests/json.rs | 0 src/{libserialize => librustc_serialize}/tests/leb128.rs | 0 src/{libserialize => librustc_serialize}/tests/opaque.rs | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename src/{libarena => librustc_arena}/Cargo.toml (100%) rename src/{libarena => librustc_arena}/lib.rs (100%) rename src/{libarena => librustc_arena}/tests.rs (100%) rename src/{libgraphviz => librustc_graphviz}/Cargo.toml (100%) rename src/{libgraphviz => librustc_graphviz}/lib.rs (100%) rename src/{libgraphviz => librustc_graphviz}/tests.rs (100%) rename src/{libfmt_macros => librustc_parse_format}/Cargo.toml (100%) rename src/{libfmt_macros => librustc_parse_format}/lib.rs (100%) rename src/{libfmt_macros => librustc_parse_format}/tests.rs (100%) rename src/{libserialize => librustc_serialize}/Cargo.toml (100%) rename src/{libserialize => librustc_serialize}/collection_impls.rs (100%) rename src/{libserialize => librustc_serialize}/json.rs (100%) rename src/{libserialize => librustc_serialize}/json/tests.rs (100%) rename src/{libserialize => librustc_serialize}/leb128.rs (100%) rename src/{libserialize => librustc_serialize}/lib.rs (100%) rename src/{libserialize => librustc_serialize}/opaque.rs (100%) rename src/{libserialize => librustc_serialize}/serialize.rs (100%) rename src/{libserialize => librustc_serialize}/tests/json.rs (100%) rename src/{libserialize => librustc_serialize}/tests/leb128.rs (100%) rename src/{libserialize => librustc_serialize}/tests/opaque.rs (100%) diff --git a/src/libarena/Cargo.toml b/src/librustc_arena/Cargo.toml similarity index 100% rename from src/libarena/Cargo.toml rename to src/librustc_arena/Cargo.toml diff --git a/src/libarena/lib.rs b/src/librustc_arena/lib.rs similarity index 100% rename from src/libarena/lib.rs rename to src/librustc_arena/lib.rs diff --git a/src/libarena/tests.rs b/src/librustc_arena/tests.rs similarity index 100% rename from src/libarena/tests.rs rename to src/librustc_arena/tests.rs diff --git a/src/libgraphviz/Cargo.toml b/src/librustc_graphviz/Cargo.toml similarity index 100% rename from src/libgraphviz/Cargo.toml rename to src/librustc_graphviz/Cargo.toml diff --git a/src/libgraphviz/lib.rs b/src/librustc_graphviz/lib.rs similarity index 100% rename from src/libgraphviz/lib.rs rename to src/librustc_graphviz/lib.rs diff --git a/src/libgraphviz/tests.rs b/src/librustc_graphviz/tests.rs similarity index 100% rename from src/libgraphviz/tests.rs rename to src/librustc_graphviz/tests.rs diff --git a/src/libfmt_macros/Cargo.toml b/src/librustc_parse_format/Cargo.toml similarity index 100% rename from src/libfmt_macros/Cargo.toml rename to src/librustc_parse_format/Cargo.toml diff --git a/src/libfmt_macros/lib.rs b/src/librustc_parse_format/lib.rs similarity index 100% rename from src/libfmt_macros/lib.rs rename to src/librustc_parse_format/lib.rs diff --git a/src/libfmt_macros/tests.rs b/src/librustc_parse_format/tests.rs similarity index 100% rename from src/libfmt_macros/tests.rs rename to src/librustc_parse_format/tests.rs diff --git a/src/libserialize/Cargo.toml b/src/librustc_serialize/Cargo.toml similarity index 100% rename from src/libserialize/Cargo.toml rename to src/librustc_serialize/Cargo.toml diff --git a/src/libserialize/collection_impls.rs b/src/librustc_serialize/collection_impls.rs similarity index 100% rename from src/libserialize/collection_impls.rs rename to src/librustc_serialize/collection_impls.rs diff --git a/src/libserialize/json.rs b/src/librustc_serialize/json.rs similarity index 100% rename from src/libserialize/json.rs rename to src/librustc_serialize/json.rs diff --git a/src/libserialize/json/tests.rs b/src/librustc_serialize/json/tests.rs similarity index 100% rename from src/libserialize/json/tests.rs rename to src/librustc_serialize/json/tests.rs diff --git a/src/libserialize/leb128.rs b/src/librustc_serialize/leb128.rs similarity index 100% rename from src/libserialize/leb128.rs rename to src/librustc_serialize/leb128.rs diff --git a/src/libserialize/lib.rs b/src/librustc_serialize/lib.rs similarity index 100% rename from src/libserialize/lib.rs rename to src/librustc_serialize/lib.rs diff --git a/src/libserialize/opaque.rs b/src/librustc_serialize/opaque.rs similarity index 100% rename from src/libserialize/opaque.rs rename to src/librustc_serialize/opaque.rs diff --git a/src/libserialize/serialize.rs b/src/librustc_serialize/serialize.rs similarity index 100% rename from src/libserialize/serialize.rs rename to src/librustc_serialize/serialize.rs diff --git a/src/libserialize/tests/json.rs b/src/librustc_serialize/tests/json.rs similarity index 100% rename from src/libserialize/tests/json.rs rename to src/librustc_serialize/tests/json.rs diff --git a/src/libserialize/tests/leb128.rs b/src/librustc_serialize/tests/leb128.rs similarity index 100% rename from src/libserialize/tests/leb128.rs rename to src/librustc_serialize/tests/leb128.rs diff --git a/src/libserialize/tests/opaque.rs b/src/librustc_serialize/tests/opaque.rs similarity index 100% rename from src/libserialize/tests/opaque.rs rename to src/librustc_serialize/tests/opaque.rs From 596b0c88cc1f496c3a50a5eb0250aed443495609 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 3 Jun 2020 01:29:02 +0800 Subject: [PATCH 577/695] Add assert to Vec with_capacity docs --- src/liballoc/vec.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 42fb1f8c737b3..22d43468771b4 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -348,9 +348,11 @@ impl Vec { /// for i in 0..10 { /// vec.push(i); /// } + /// assert_eq!(vec.capacity(), 10); /// /// // ...but this may make the vector reallocate /// vec.push(11); + /// assert!(vec.capacity() >= 11); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] From 11d951492ce68ef692c1d9a77bebde22b57cf0c6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 2 Jun 2020 20:03:40 +0300 Subject: [PATCH 578/695] Make things build again --- Cargo.lock | 124 +++++++++--------- src/librustc_arena/Cargo.toml | 4 +- src/librustc_ast/Cargo.toml | 2 +- src/librustc_ast_lowering/Cargo.toml | 2 +- src/librustc_attr/Cargo.toml | 2 +- src/librustc_builtin_macros/Cargo.toml | 2 +- src/librustc_codegen_llvm/Cargo.toml | 2 +- src/librustc_codegen_ssa/Cargo.toml | 2 +- src/librustc_data_structures/Cargo.toml | 4 +- src/librustc_driver/Cargo.toml | 2 +- src/librustc_errors/Cargo.toml | 2 +- src/librustc_expand/Cargo.toml | 2 +- src/librustc_graphviz/Cargo.toml | 4 +- src/librustc_hir/Cargo.toml | 2 +- src/librustc_incremental/Cargo.toml | 4 +- src/librustc_index/Cargo.toml | 2 +- src/librustc_infer/Cargo.toml | 4 +- src/librustc_interface/Cargo.toml | 2 +- src/librustc_metadata/Cargo.toml | 2 +- src/librustc_middle/Cargo.toml | 4 +- src/librustc_mir/Cargo.toml | 4 +- .../borrow_check/region_infer/graphviz.rs | 2 +- src/librustc_mir/util/graphviz.rs | 2 +- src/librustc_mir_build/Cargo.toml | 4 +- src/librustc_parse_format/Cargo.toml | 4 +- src/librustc_query_system/Cargo.toml | 4 +- src/librustc_resolve/Cargo.toml | 2 +- src/librustc_serialize/Cargo.toml | 4 +- src/librustc_session/Cargo.toml | 2 +- src/librustc_span/Cargo.toml | 4 +- src/librustc_target/Cargo.toml | 2 +- src/librustc_trait_selection/Cargo.toml | 2 +- src/librustc_typeck/Cargo.toml | 2 +- 33 files changed, 106 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6cfedd4a56da8..90bc42360aa31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,14 +69,6 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" -[[package]] -name = "arena" -version = "0.0.0" -dependencies = [ - "rustc_data_structures", - "smallvec 1.4.0", -] - [[package]] name = "argon2rs" version = "0.2.5" @@ -1200,14 +1192,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "fmt_macros" -version = "0.0.0" -dependencies = [ - "rustc_lexer", - "rustc_span", -] - [[package]] name = "fnv" version = "1.0.6" @@ -1389,10 +1373,6 @@ dependencies = [ "regex", ] -[[package]] -name = "graphviz" -version = "0.0.0" - [[package]] name = "h2" version = "0.1.25" @@ -3599,6 +3579,14 @@ dependencies = [ "smallvec 1.4.0", ] +[[package]] +name = "rustc_arena" +version = "0.0.0" +dependencies = [ + "rustc_data_structures", + "smallvec 1.4.0", +] + [[package]] name = "rustc_ast" version = "0.0.0" @@ -3609,9 +3597,9 @@ dependencies = [ "rustc_index", "rustc_lexer", "rustc_macros", + "rustc_serialize", "rustc_span", "scoped-tls", - "serialize", "smallvec 1.4.0", ] @@ -3619,8 +3607,8 @@ dependencies = [ name = "rustc_ast_lowering" version = "0.0.0" dependencies = [ - "arena", "log", + "rustc_arena", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -3670,9 +3658,9 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_macros", + "rustc_serialize", "rustc_session", "rustc_span", - "serialize", "version_check", ] @@ -3680,7 +3668,6 @@ dependencies = [ name = "rustc_builtin_macros" version = "0.0.0" dependencies = [ - "fmt_macros", "log", "rustc_ast", "rustc_ast_pretty", @@ -3690,6 +3677,7 @@ dependencies = [ "rustc_expand", "rustc_feature", "rustc_parse", + "rustc_parse_format", "rustc_session", "rustc_span", "rustc_target", @@ -3718,10 +3706,10 @@ dependencies = [ "rustc_index", "rustc_llvm", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", - "serialize", "smallvec 1.4.0", ] @@ -3746,11 +3734,11 @@ dependencies = [ "rustc_incremental", "rustc_index", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_symbol_mangling", "rustc_target", - "serialize", "tempfile", ] @@ -3762,7 +3750,6 @@ dependencies = [ "cfg-if", "crossbeam-utils 0.7.2", "ena 0.14.0", - "graphviz", "indexmap", "jobserver", "lazy_static", @@ -3774,8 +3761,9 @@ dependencies = [ "rustc-hash", "rustc-rayon", "rustc-rayon-core", + "rustc_graphviz", "rustc_index", - "serialize", + "rustc_serialize", "smallvec 1.4.0", "stable_deref_trait", "stacker", @@ -3807,10 +3795,10 @@ dependencies = [ "rustc_parse", "rustc_plugin_impl", "rustc_save_analysis", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", - "serialize", "winapi 0.3.8", ] @@ -3826,8 +3814,8 @@ dependencies = [ "atty", "log", "rustc_data_structures", + "rustc_serialize", "rustc_span", - "serialize", "termcolor", "termize", "unicode-width", @@ -3848,9 +3836,9 @@ dependencies = [ "rustc_feature", "rustc_lexer", "rustc_parse", + "rustc_serialize", "rustc_session", "rustc_span", - "serialize", "smallvec 1.4.0", ] @@ -3867,6 +3855,10 @@ dependencies = [ name = "rustc_fs_util" version = "0.0.0" +[[package]] +name = "rustc_graphviz" +version = "0.0.0" + [[package]] name = "rustc_hir" version = "0.0.0" @@ -3877,9 +3869,9 @@ dependencies = [ "rustc_data_structures", "rustc_index", "rustc_macros", + "rustc_serialize", "rustc_span", "rustc_target", - "serialize", "smallvec 1.4.0", ] @@ -3898,24 +3890,24 @@ dependencies = [ name = "rustc_incremental" version = "0.0.0" dependencies = [ - "graphviz", "log", "rand 0.7.3", "rustc_ast", "rustc_data_structures", "rustc_fs_util", + "rustc_graphviz", "rustc_hir", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", - "serialize", ] [[package]] name = "rustc_index" version = "0.0.0" dependencies = [ - "serialize", + "rustc_serialize", "smallvec 1.4.0", ] @@ -3923,19 +3915,19 @@ dependencies = [ name = "rustc_infer" version = "0.0.0" dependencies = [ - "graphviz", "log", "rustc_ast", "rustc_data_structures", "rustc_errors", + "rustc_graphviz", "rustc_hir", "rustc_index", "rustc_macros", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", - "serialize", "smallvec 1.4.0", ] @@ -3969,6 +3961,7 @@ dependencies = [ "rustc_plugin_impl", "rustc_privacy", "rustc_resolve", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_symbol_mangling", @@ -3977,7 +3970,6 @@ dependencies = [ "rustc_traits", "rustc_ty", "rustc_typeck", - "serialize", "smallvec 1.4.0", "tempfile", "winapi 0.3.8", @@ -4047,10 +4039,10 @@ dependencies = [ "rustc_hir_pretty", "rustc_index", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", - "serialize", "smallvec 1.4.0", "stable_deref_trait", "winapi 0.3.8", @@ -4060,7 +4052,6 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "arena", "bitflags", "byteorder", "chalk-ir", @@ -4069,6 +4060,7 @@ dependencies = [ "polonius-engine", "rustc-rayon-core", "rustc_apfloat", + "rustc_arena", "rustc_ast", "rustc_attr", "rustc_data_structures", @@ -4078,11 +4070,11 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_query_system", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", "scoped-tls", - "serialize", "smallvec 1.4.0", ] @@ -4091,7 +4083,6 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "either", - "graphviz", "itertools 0.8.0", "log", "log_settings", @@ -4101,17 +4092,18 @@ dependencies = [ "rustc_attr", "rustc_data_structures", "rustc_errors", + "rustc_graphviz", "rustc_hir", "rustc_index", "rustc_infer", "rustc_lexer", "rustc_macros", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", "rustc_trait_selection", - "serialize", "smallvec 1.4.0", ] @@ -4119,9 +4111,9 @@ dependencies = [ name = "rustc_mir_build" version = "0.0.0" dependencies = [ - "arena", "log", "rustc_apfloat", + "rustc_arena", "rustc_ast", "rustc_attr", "rustc_data_structures", @@ -4130,11 +4122,11 @@ dependencies = [ "rustc_index", "rustc_infer", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", "rustc_trait_selection", - "serialize", "smallvec 1.4.0", ] @@ -4155,6 +4147,14 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "rustc_parse_format" +version = "0.0.0" +dependencies = [ + "rustc_lexer", + "rustc_span", +] + [[package]] name = "rustc_passes" version = "0.0.0" @@ -4206,15 +4206,15 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ - "arena", "log", "parking_lot 0.10.2", "rustc-rayon-core", + "rustc_arena", "rustc_data_structures", "rustc_errors", "rustc_index", + "rustc_serialize", "rustc_span", - "serialize", "smallvec 1.4.0", ] @@ -4222,9 +4222,9 @@ dependencies = [ name = "rustc_resolve" version = "0.0.0" dependencies = [ - "arena", "bitflags", "log", + "rustc_arena", "rustc_ast", "rustc_ast_lowering", "rustc_ast_pretty", @@ -4260,6 +4260,14 @@ dependencies = [ "serde_json", ] +[[package]] +name = "rustc_serialize" +version = "0.0.0" +dependencies = [ + "indexmap", + "smallvec 1.4.0", +] + [[package]] name = "rustc_session" version = "0.0.0" @@ -4272,24 +4280,24 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_fs_util", + "rustc_serialize", "rustc_span", "rustc_target", - "serialize", ] [[package]] name = "rustc_span" version = "0.0.0" dependencies = [ - "arena", "cfg-if", "log", "md-5", + "rustc_arena", "rustc_data_structures", "rustc_index", "rustc_macros", + "rustc_serialize", "scoped-tls", - "serialize", "sha-1", "unicode-width", ] @@ -4319,8 +4327,8 @@ dependencies = [ "rustc_data_structures", "rustc_index", "rustc_macros", + "rustc_serialize", "rustc_span", - "serialize", ] [[package]] @@ -4337,7 +4345,6 @@ checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee" name = "rustc_trait_selection" version = "0.0.0" dependencies = [ - "fmt_macros", "log", "rustc_ast", "rustc_attr", @@ -4348,6 +4355,7 @@ dependencies = [ "rustc_infer", "rustc_macros", "rustc_middle", + "rustc_parse_format", "rustc_session", "rustc_span", "rustc_target", @@ -4393,8 +4401,8 @@ dependencies = [ name = "rustc_typeck" version = "0.0.0" dependencies = [ - "arena", "log", + "rustc_arena", "rustc_ast", "rustc_attr", "rustc_data_structures", @@ -4657,14 +4665,6 @@ dependencies = [ "url 1.7.2", ] -[[package]] -name = "serialize" -version = "0.0.0" -dependencies = [ - "indexmap", - "smallvec 1.4.0", -] - [[package]] name = "sha-1" version = "0.8.2" diff --git a/src/librustc_arena/Cargo.toml b/src/librustc_arena/Cargo.toml index 5158aab8b7dc5..dfae956e2b6d5 100644 --- a/src/librustc_arena/Cargo.toml +++ b/src/librustc_arena/Cargo.toml @@ -1,11 +1,11 @@ [package] authors = ["The Rust Project Developers"] -name = "arena" +name = "rustc_arena" version = "0.0.0" edition = "2018" [lib] -name = "arena" +name = "rustc_arena" path = "lib.rs" [dependencies] diff --git a/src/librustc_ast/Cargo.toml b/src/librustc_ast/Cargo.toml index 7d105f9e8863d..6bd65fd5f96c7 100644 --- a/src/librustc_ast/Cargo.toml +++ b/src/librustc_ast/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } log = "0.4" scoped-tls = "1.0" rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_ast_lowering/Cargo.toml b/src/librustc_ast_lowering/Cargo.toml index b477b75db5adc..8a49b157816f6 100644 --- a/src/librustc_ast_lowering/Cargo.toml +++ b/src/librustc_ast_lowering/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -arena = { path = "../libarena" } +arena = { path = "../librustc_arena", package = "rustc_arena" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_hir = { path = "../librustc_hir" } diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml index d7af7fe6143e5..677796a8df0b3 100644 --- a/src/librustc_attr/Cargo.toml +++ b/src/librustc_attr/Cargo.toml @@ -12,7 +12,7 @@ doctest = false [dependencies] rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_errors = { path = "../librustc_errors" } rustc_span = { path = "../librustc_span" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_builtin_macros/Cargo.toml b/src/librustc_builtin_macros/Cargo.toml index c15438bde440e..7e7c9bf81f473 100644 --- a/src/librustc_builtin_macros/Cargo.toml +++ b/src/librustc_builtin_macros/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -fmt_macros = { path = "../libfmt_macros" } +fmt_macros = { path = "../librustc_parse_format", package = "rustc_parse_format" } log = "0.4" rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_attr = { path = "../librustc_attr" } diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index 64e66595d92d9..bedefcc30ed8c 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -29,7 +29,7 @@ rustc_incremental = { path = "../librustc_incremental" } rustc_index = { path = "../librustc_index" } rustc_llvm = { path = "../librustc_llvm" } rustc_session = { path = "../librustc_session" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index e8bfc87aef5ea..eeb6b4aabcf29 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -19,7 +19,7 @@ libc = "0.2.50" jobserver = "0.1.11" tempfile = "3.1" -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc_middle = { path = "../librustc_middle" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 67721220526ca..be887ba9adb56 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -16,8 +16,8 @@ log = "0.4" jobserver_crate = { version = "0.1.13", package = "jobserver" } lazy_static = "1" once_cell = { version = "1", features = ["parking_lot"] } -rustc_serialize = { path = "../libserialize", package = "serialize" } -graphviz = { path = "../libgraphviz" } +rustc_serialize = { path = "../librustc_serialize" } +graphviz = { path = "../librustc_graphviz", package = "rustc_graphviz" } cfg-if = "0.1.2" crossbeam-utils = { version = "0.7", features = ["nightly"] } stable_deref_trait = "1.0.0" diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index cfd103aed3240..75d6592076655 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -32,7 +32,7 @@ rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } rustc_session = { path = "../librustc_session" } rustc_error_codes = { path = "../librustc_error_codes" } rustc_interface = { path = "../librustc_interface" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index b8340b1a1df6a..ed1f43e567da6 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -11,7 +11,7 @@ doctest = false [dependencies] log = "0.4" -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_span = { path = "../librustc_span" } rustc_data_structures = { path = "../librustc_data_structures" } unicode-width = "0.1.4" diff --git a/src/librustc_expand/Cargo.toml b/src/librustc_expand/Cargo.toml index 3cb79030771b8..ef617acfe1314 100644 --- a/src/librustc_expand/Cargo.toml +++ b/src/librustc_expand/Cargo.toml @@ -11,7 +11,7 @@ path = "lib.rs" doctest = false [dependencies] -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } log = "0.4" rustc_span = { path = "../librustc_span" } rustc_ast_pretty = { path = "../librustc_ast_pretty" } diff --git a/src/librustc_graphviz/Cargo.toml b/src/librustc_graphviz/Cargo.toml index 4a6e41f760319..9a5e78a560cf0 100644 --- a/src/librustc_graphviz/Cargo.toml +++ b/src/librustc_graphviz/Cargo.toml @@ -1,9 +1,9 @@ [package] authors = ["The Rust Project Developers"] -name = "graphviz" +name = "rustc_graphviz" version = "0.0.0" edition = "2018" [lib] -name = "graphviz" +name = "rustc_graphviz" path = "lib.rs" diff --git a/src/librustc_hir/Cargo.toml b/src/librustc_hir/Cargo.toml index 811440fdeb987..1b91d769c7047 100644 --- a/src/librustc_hir/Cargo.toml +++ b/src/librustc_hir/Cargo.toml @@ -15,7 +15,7 @@ rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_index = { path = "../librustc_index" } rustc_span = { path = "../librustc_span" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_ast = { path = "../librustc_ast" } lazy_static = "1" log = { version = "0.4", features = ["release_max_level_info", "std"] } diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index 5caf1d411e637..8a9b69ce51e32 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -10,13 +10,13 @@ path = "lib.rs" doctest = false [dependencies] -graphviz = { path = "../libgraphviz" } +graphviz = { path = "../librustc_graphviz", package = "rustc_graphviz" } log = "0.4" rand = "0.7" rustc_middle = { path = "../librustc_middle" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_hir = { path = "../librustc_hir" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc_fs_util = { path = "../librustc_fs_util" } diff --git a/src/librustc_index/Cargo.toml b/src/librustc_index/Cargo.toml index 1435297f27ada..f0422b1af1b97 100644 --- a/src/librustc_index/Cargo.toml +++ b/src/librustc_index/Cargo.toml @@ -10,5 +10,5 @@ path = "lib.rs" doctest = false [dependencies] -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_infer/Cargo.toml b/src/librustc_infer/Cargo.toml index fa8e5a2ab78b4..54d1610f49eb9 100644 --- a/src/librustc_infer/Cargo.toml +++ b/src/librustc_infer/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -graphviz = { path = "../libgraphviz" } +graphviz = { path = "../librustc_graphviz", package = "rustc_graphviz" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_middle = { path = "../librustc_middle" } rustc_data_structures = { path = "../librustc_data_structures" } @@ -19,7 +19,7 @@ rustc_hir = { path = "../librustc_hir" } rustc_index = { path = "../librustc_index" } rustc_macros = { path = "../librustc_macros" } rustc_session = { path = "../librustc_session" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_span = { path = "../librustc_span" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 2963eb29bc170..112dc7037f588 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -21,7 +21,7 @@ rustc_expand = { path = "../librustc_expand" } rustc_parse = { path = "../librustc_parse" } rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_middle = { path = "../librustc_middle" } rustc_ast_lowering = { path = "../librustc_ast_lowering" } rustc_ast_passes = { path = "../librustc_ast_passes" } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index b03e884cdaf7a..7bbe7567d2924 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -23,7 +23,7 @@ rustc_hir = { path = "../librustc_hir" } rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_target = { path = "../librustc_target" } rustc_index = { path = "../librustc_index" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } stable_deref_trait = "1.0.0" rustc_ast = { path = "../librustc_ast" } rustc_expand = { path = "../librustc_expand" } diff --git a/src/librustc_middle/Cargo.toml b/src/librustc_middle/Cargo.toml index 0bb32438b7276..1a7e3b36cb002 100644 --- a/src/librustc_middle/Cargo.toml +++ b/src/librustc_middle/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -arena = { path = "../libarena" } +arena = { path = "../librustc_arena", package = "rustc_arena" } bitflags = "1.2.1" scoped-tls = "1.0" log = { version = "0.4", features = ["release_max_level_info", "std"] } @@ -26,7 +26,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_query_system = { path = "../librustc_query_system" } rustc_errors = { path = "../librustc_errors" } rustc_index = { path = "../librustc_index" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } byteorder = { version = "1.3" } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index d922a83232901..bfe3b22962e79 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -11,7 +11,7 @@ doctest = false [dependencies] either = "1.5.0" -dot = { path = "../libgraphviz", package = "graphviz" } +dot = { path = "../librustc_graphviz", package = "rustc_graphviz" } itertools = "0.8" log = "0.4" log_settings = "0.1.1" @@ -25,7 +25,7 @@ rustc_index = { path = "../librustc_index" } rustc_infer = { path = "../librustc_infer" } rustc_lexer = { path = "../librustc_lexer" } rustc_macros = { path = "../librustc_macros" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_session = { path = "../librustc_session" } rustc_target = { path = "../librustc_target" } rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_mir/borrow_check/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/region_infer/graphviz.rs index 39b396ba4e7d3..6a60917e22c7c 100644 --- a/src/librustc_mir/borrow_check/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/region_infer/graphviz.rs @@ -1,5 +1,5 @@ //! This module provides linkage between RegionInferenceContext and -//! libgraphviz traits, specialized to attaching borrowck analysis +//! librustc_graphviz traits, specialized to attaching borrowck analysis //! data to rendered labels. use std::borrow::Cow; diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index fb862b926d782..3583223b5fe9c 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -76,7 +76,7 @@ where /// Write a graphviz HTML-styled label for the given basic block, with /// all necessary escaping already performed. (This is suitable for /// emitting directly, as is done in this module, or for use with the -/// LabelText::HtmlStr from libgraphviz.) +/// LabelText::HtmlStr from librustc_graphviz.) /// /// `init` and `fini` are callbacks for emitting additional rows of /// data (using HTML enclosed with `` in the emitted text). diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml index 4a64cf74787ac..54fb8fb171c6e 100644 --- a/src/librustc_mir_build/Cargo.toml +++ b/src/librustc_mir_build/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -arena = { path = "../libarena" } +arena = { path = "../librustc_arena", package = "rustc_arena" } log = "0.4" rustc_middle = { path = "../librustc_middle" } rustc_apfloat = { path = "../librustc_apfloat" } @@ -20,7 +20,7 @@ rustc_index = { path = "../librustc_index" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } rustc_infer = { path = "../librustc_infer" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_parse_format/Cargo.toml b/src/librustc_parse_format/Cargo.toml index 01608701a79dc..646509569f3a5 100644 --- a/src/librustc_parse_format/Cargo.toml +++ b/src/librustc_parse_format/Cargo.toml @@ -1,11 +1,11 @@ [package] authors = ["The Rust Project Developers"] -name = "fmt_macros" +name = "rustc_parse_format" version = "0.0.0" edition = "2018" [lib] -name = "fmt_macros" +name = "rustc_parse_format" path = "lib.rs" [dependencies] diff --git a/src/librustc_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml index 392e19e1f4471..7bf208d2f86e1 100644 --- a/src/librustc_query_system/Cargo.toml +++ b/src/librustc_query_system/Cargo.toml @@ -10,13 +10,13 @@ path = "lib.rs" doctest = false [dependencies] -arena = { path = "../libarena" } +arena = { path = "../librustc_arena", package = "rustc_arena" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc-rayon-core = "0.3.0" rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_index = { path = "../librustc_index" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_span = { path = "../librustc_span" } parking_lot = "0.10" smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 420a82d6d2ced..0259e342f43d7 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -14,7 +14,7 @@ doctest = false bitflags = "1.2.1" log = "0.4" rustc_ast = { path = "../librustc_ast" } -arena = { path = "../libarena" } +arena = { path = "../librustc_arena", package = "rustc_arena" } rustc_middle = { path = "../librustc_middle" } rustc_ast_lowering = { path = "../librustc_ast_lowering" } rustc_ast_pretty = { path = "../librustc_ast_pretty" } diff --git a/src/librustc_serialize/Cargo.toml b/src/librustc_serialize/Cargo.toml index 96a0d51bc716d..84206df50ccee 100644 --- a/src/librustc_serialize/Cargo.toml +++ b/src/librustc_serialize/Cargo.toml @@ -1,11 +1,11 @@ [package] authors = ["The Rust Project Developers"] -name = "serialize" +name = "rustc_serialize" version = "0.0.0" edition = "2018" [lib] -name = "serialize" +name = "rustc_serialize" path = "lib.rs" [dependencies] diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml index 705c115cf3c85..4d57c6384ddbd 100644 --- a/src/librustc_session/Cargo.toml +++ b/src/librustc_session/Cargo.toml @@ -14,7 +14,7 @@ log = "0.4" rustc_errors = { path = "../librustc_errors" } rustc_feature = { path = "../librustc_feature" } rustc_target = { path = "../librustc_target" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_span = { path = "../librustc_span" } rustc_fs_util = { path = "../librustc_fs_util" } diff --git a/src/librustc_span/Cargo.toml b/src/librustc_span/Cargo.toml index 1c2721260d69b..9cb0e54080aab 100644 --- a/src/librustc_span/Cargo.toml +++ b/src/librustc_span/Cargo.toml @@ -10,11 +10,11 @@ path = "lib.rs" doctest = false [dependencies] -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_index = { path = "../librustc_index" } -arena = { path = "../libarena" } +arena = { path = "../librustc_arena", package = "rustc_arena" } scoped-tls = "1.0" unicode-width = "0.1.4" cfg-if = "0.1.2" diff --git a/src/librustc_target/Cargo.toml b/src/librustc_target/Cargo.toml index 0e234036879e5..c73490e451320 100644 --- a/src/librustc_target/Cargo.toml +++ b/src/librustc_target/Cargo.toml @@ -13,6 +13,6 @@ bitflags = "1.2.1" log = "0.4" rustc_data_structures = { path = "../librustc_data_structures" } rustc_macros = { path = "../librustc_macros" } -rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_serialize = { path = "../librustc_serialize" } rustc_span = { path = "../librustc_span" } rustc_index = { path = "../librustc_index" } diff --git a/src/librustc_trait_selection/Cargo.toml b/src/librustc_trait_selection/Cargo.toml index 254695e53e04d..a1d984dcef0ff 100644 --- a/src/librustc_trait_selection/Cargo.toml +++ b/src/librustc_trait_selection/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -fmt_macros = { path = "../libfmt_macros" } +fmt_macros = { path = "../librustc_parse_format", package = "rustc_parse_format" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_attr = { path = "../librustc_attr" } rustc_middle = { path = "../librustc_middle" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 8aaa29bc582fc..b505b59806f35 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -11,7 +11,7 @@ test = false doctest = false [dependencies] -arena = { path = "../libarena" } +arena = { path = "../librustc_arena", package = "rustc_arena" } log = "0.4" rustc_middle = { path = "../librustc_middle" } rustc_attr = { path = "../librustc_attr" } From 2b79413491ed02b7bdc8236f43811aedde0fe325 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 2 Jun 2020 20:19:49 +0300 Subject: [PATCH 579/695] Rename the crates in source code --- clippy_lints/src/write.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index dfa6223f1b9dd..006503b546edf 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -352,7 +352,7 @@ impl Write { tts: &TokenStream, is_write: bool, ) -> (Option, Option) { - use fmt_macros::{ + use rustc_parse_format::{ AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, ParseMode, Parser, Piece, }; From 283e5b4106771f9d6ee6e081c07d4a174b51441e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 2 Jun 2020 20:19:49 +0300 Subject: [PATCH 580/695] Rename the crates in source code --- src/librustc_ast_lowering/Cargo.toml | 2 +- src/librustc_ast_lowering/lib.rs | 2 +- src/librustc_builtin_macros/Cargo.toml | 2 +- src/librustc_builtin_macros/asm.rs | 3 +-- src/librustc_builtin_macros/format.rs | 3 +-- src/librustc_data_structures/Cargo.toml | 2 +- .../obligation_forest/graphviz.rs | 2 +- src/librustc_graphviz/lib.rs | 6 +++--- src/librustc_incremental/Cargo.toml | 2 +- src/librustc_incremental/assert_dep_graph.rs | 2 +- src/librustc_infer/Cargo.toml | 2 +- src/librustc_middle/Cargo.toml | 2 +- src/librustc_middle/arena.rs | 2 +- src/librustc_mir/Cargo.toml | 2 +- .../borrow_check/region_infer/graphviz.rs | 1 + src/librustc_mir/dataflow/framework/engine.rs | 1 + src/librustc_mir/dataflow/framework/graphviz.rs | 1 + src/librustc_mir/util/graphviz.rs | 1 + src/librustc_mir_build/Cargo.toml | 2 +- src/librustc_mir_build/hair/pattern/_match.rs | 3 +-- src/librustc_mir_build/hair/pattern/check_match.rs | 2 +- src/librustc_query_system/Cargo.toml | 2 +- src/librustc_query_system/query/caches.rs | 2 +- src/librustc_resolve/Cargo.toml | 2 +- src/librustc_resolve/lib.rs | 13 +++++++------ src/librustc_span/Cargo.toml | 2 +- src/librustc_span/symbol.rs | 2 +- src/librustc_trait_selection/Cargo.toml | 2 +- .../traits/on_unimplemented.rs | 3 +-- src/librustc_typeck/Cargo.toml | 2 +- src/librustc_typeck/variance/mod.rs | 3 ++- src/librustc_typeck/variance/terms.rs | 2 +- .../run-make-fulldeps/save-analysis-fail/foo.rs | 4 ++-- src/test/run-make-fulldeps/save-analysis/foo.rs | 4 ++-- src/test/ui-fulldeps/dropck-tarena-cycle-checked.rs | 4 ++-- src/test/ui-fulldeps/dropck-tarena-unsound-drop.rs | 4 ++-- src/test/ui-fulldeps/dropck_tarena_sound_drop.rs | 4 ++-- src/test/ui-fulldeps/regions-mock-tcx.rs | 4 ++-- src/tools/clippy/clippy_lints/src/write.rs | 2 +- 39 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/librustc_ast_lowering/Cargo.toml b/src/librustc_ast_lowering/Cargo.toml index 8a49b157816f6..d71eb4fcd5c27 100644 --- a/src/librustc_ast_lowering/Cargo.toml +++ b/src/librustc_ast_lowering/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -arena = { path = "../librustc_arena", package = "rustc_arena" } +rustc_arena = { path = "../librustc_arena" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_hir = { path = "../librustc_hir" } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 3aab54ea90949..1f8c68f75e943 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -85,7 +85,7 @@ mod path; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; -rustc_hir::arena_types!(::arena::declare_arena, [], 'tcx); +rustc_hir::arena_types!(rustc_arena::declare_arena, [], 'tcx); struct LoweringContext<'a, 'hir: 'a> { crate_root: Option, diff --git a/src/librustc_builtin_macros/Cargo.toml b/src/librustc_builtin_macros/Cargo.toml index 7e7c9bf81f473..fdb6c359052d0 100644 --- a/src/librustc_builtin_macros/Cargo.toml +++ b/src/librustc_builtin_macros/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -fmt_macros = { path = "../librustc_parse_format", package = "rustc_parse_format" } +rustc_parse_format = { path = "../librustc_parse_format" } log = "0.4" rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_attr = { path = "../librustc_attr" } diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index fad638f6f2819..aabd5b5b5c31b 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -1,5 +1,3 @@ -use fmt_macros as parse; - use rustc_ast::ast; use rustc_ast::ptr::P; use rustc_ast::token; @@ -8,6 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::{self, *}; use rustc_parse::parser::Parser; +use rustc_parse_format as parse; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{InnerSpan, Span}; diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs index eed01b262bf0c..e574b076bf84c 100644 --- a/src/librustc_builtin_macros/format.rs +++ b/src/librustc_builtin_macros/format.rs @@ -1,8 +1,6 @@ use ArgumentType::*; use Position::*; -use fmt_macros as parse; - use rustc_ast::ast; use rustc_ast::ptr::P; use rustc_ast::token; @@ -10,6 +8,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; use rustc_expand::base::{self, *}; +use rustc_parse_format as parse; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span}; diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index be887ba9adb56..bf2ab0787cb70 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -17,7 +17,7 @@ jobserver_crate = { version = "0.1.13", package = "jobserver" } lazy_static = "1" once_cell = { version = "1", features = ["parking_lot"] } rustc_serialize = { path = "../librustc_serialize" } -graphviz = { path = "../librustc_graphviz", package = "rustc_graphviz" } +rustc_graphviz = { path = "../librustc_graphviz" } cfg-if = "0.1.2" crossbeam-utils = { version = "0.7", features = ["nightly"] } stable_deref_trait = "1.0.0" diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/src/librustc_data_structures/obligation_forest/graphviz.rs index e1784f44fd112..3a268e4b4f432 100644 --- a/src/librustc_data_structures/obligation_forest/graphviz.rs +++ b/src/librustc_data_structures/obligation_forest/graphviz.rs @@ -1,5 +1,5 @@ use crate::obligation_forest::{ForestObligation, ObligationForest}; -use graphviz as dot; +use rustc_graphviz as dot; use std::env::var_os; use std::fs::File; use std::io::BufWriter; diff --git a/src/librustc_graphviz/lib.rs b/src/librustc_graphviz/lib.rs index a53e0012ca221..4339092b63e85 100644 --- a/src/librustc_graphviz/lib.rs +++ b/src/librustc_graphviz/lib.rs @@ -40,7 +40,7 @@ //! #![feature(rustc_private)] //! //! use std::io::Write; -//! use graphviz as dot; +//! use rustc_graphviz as dot; //! //! type Nd = isize; //! type Ed = (isize,isize); @@ -145,7 +145,7 @@ //! #![feature(rustc_private)] //! //! use std::io::Write; -//! use graphviz as dot; +//! use rustc_graphviz as dot; //! //! type Nd = usize; //! type Ed<'a> = &'a (usize, usize); @@ -207,7 +207,7 @@ //! #![feature(rustc_private)] //! //! use std::io::Write; -//! use graphviz as dot; +//! use rustc_graphviz as dot; //! //! type Nd<'a> = (usize, &'a str); //! type Ed<'a> = (Nd<'a>, Nd<'a>); diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index 8a9b69ce51e32..7b3030fa1d9c1 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -graphviz = { path = "../librustc_graphviz", package = "rustc_graphviz" } +rustc_graphviz = { path = "../librustc_graphviz" } log = "0.4" rand = "0.7" rustc_middle = { path = "../librustc_middle" } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 807ae586348e9..b1665d9e1aeb3 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -33,10 +33,10 @@ //! fn baz() { foo(); } //! ``` -use graphviz as dot; use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING}; +use rustc_graphviz as dot; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; diff --git a/src/librustc_infer/Cargo.toml b/src/librustc_infer/Cargo.toml index 54d1610f49eb9..06fc7ecf95f26 100644 --- a/src/librustc_infer/Cargo.toml +++ b/src/librustc_infer/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -graphviz = { path = "../librustc_graphviz", package = "rustc_graphviz" } +rustc_graphviz = { path = "../librustc_graphviz" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_middle = { path = "../librustc_middle" } rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_middle/Cargo.toml b/src/librustc_middle/Cargo.toml index 1a7e3b36cb002..0c22672d5fb7d 100644 --- a/src/librustc_middle/Cargo.toml +++ b/src/librustc_middle/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -arena = { path = "../librustc_arena", package = "rustc_arena" } +rustc_arena = { path = "../librustc_arena" } bitflags = "1.2.1" scoped-tls = "1.0" log = { version = "0.4", features = ["release_max_level_info", "std"] } diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index d5212ec5c3081..75228350c6c45 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -88,4 +88,4 @@ macro_rules! arena_types { ) } -arena_types!(arena::declare_arena, [], 'tcx); +arena_types!(rustc_arena::declare_arena, [], 'tcx); diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index bfe3b22962e79..aebce78e4018b 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -11,7 +11,7 @@ doctest = false [dependencies] either = "1.5.0" -dot = { path = "../librustc_graphviz", package = "rustc_graphviz" } +rustc_graphviz = { path = "../librustc_graphviz" } itertools = "0.8" log = "0.4" log_settings = "0.1.1" diff --git a/src/librustc_mir/borrow_check/region_infer/graphviz.rs b/src/librustc_mir/borrow_check/region_infer/graphviz.rs index 6a60917e22c7c..a272e922a504e 100644 --- a/src/librustc_mir/borrow_check/region_infer/graphviz.rs +++ b/src/librustc_mir/borrow_check/region_infer/graphviz.rs @@ -7,6 +7,7 @@ use std::io::{self, Write}; use super::*; use crate::borrow_check::constraints::OutlivesConstraint; +use rustc_graphviz as dot; impl<'tcx> RegionInferenceContext<'tcx> { /// Write out the region constraint graph. diff --git a/src/librustc_mir/dataflow/framework/engine.rs b/src/librustc_mir/dataflow/framework/engine.rs index 32e569fdc3589..243b3679f2984 100644 --- a/src/librustc_mir/dataflow/framework/engine.rs +++ b/src/librustc_mir/dataflow/framework/engine.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use rustc_ast::ast; use rustc_data_structures::work_queue::WorkQueue; +use rustc_graphviz as dot; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; diff --git a/src/librustc_mir/dataflow/framework/graphviz.rs b/src/librustc_mir/dataflow/framework/graphviz.rs index e3ba26eaf8b37..896616a2175ac 100644 --- a/src/librustc_mir/dataflow/framework/graphviz.rs +++ b/src/librustc_mir/dataflow/framework/graphviz.rs @@ -3,6 +3,7 @@ use std::cell::RefCell; use std::{io, ops, str}; +use rustc_graphviz as dot; use rustc_hir::def_id::DefId; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_index::vec::{Idx, IndexVec}; diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index 3583223b5fe9c..a0a82ce3b9df9 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -1,3 +1,4 @@ +use rustc_graphviz as dot; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; use rustc_middle::mir::*; diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml index 54fb8fb171c6e..401a5009e3cf7 100644 --- a/src/librustc_mir_build/Cargo.toml +++ b/src/librustc_mir_build/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -arena = { path = "../librustc_arena", package = "rustc_arena" } +rustc_arena = { path = "../librustc_arena" } log = "0.4" rustc_middle = { path = "../librustc_middle" } rustc_apfloat = { path = "../librustc_apfloat" } diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 575ddcef99715..2de6d9fe3d480 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -280,6 +280,7 @@ use rustc_index::vec::Idx; use super::{compare_const_vals, PatternFoldable, PatternFolder}; use super::{FieldPat, Pat, PatKind, PatRange}; +use rustc_arena::TypedArena; use rustc_attr::{SignedInt, UnsignedInt}; use rustc_errors::ErrorReported; use rustc_hir::def_id::DefId; @@ -292,8 +293,6 @@ use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; -use arena::TypedArena; - use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; use std::cmp::{self, max, min, Ordering}; diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index 707502640e05c..4d97a19f4086b 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -3,7 +3,7 @@ use super::_match::WitnessPreference::*; use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}; use super::{PatCtxt, PatKind, PatternError}; -use arena::TypedArena; +use rustc_arena::TypedArena; use rustc_ast::ast::Mutability; use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; diff --git a/src/librustc_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml index 7bf208d2f86e1..73d50f84fe836 100644 --- a/src/librustc_query_system/Cargo.toml +++ b/src/librustc_query_system/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -arena = { path = "../librustc_arena", package = "rustc_arena" } +rustc_arena = { path = "../librustc_arena" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc-rayon-core = "0.3.0" rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_query_system/query/caches.rs b/src/librustc_query_system/query/caches.rs index 6a47abc5b4612..f0beec0a17726 100644 --- a/src/librustc_query_system/query/caches.rs +++ b/src/librustc_query_system/query/caches.rs @@ -2,7 +2,7 @@ use crate::dep_graph::DepNodeIndex; use crate::query::plumbing::{QueryLookup, QueryState}; use crate::query::QueryContext; -use arena::TypedArena; +use rustc_arena::TypedArena; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sharded::Sharded; use rustc_data_structures::sync::WorkerLocal; diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 0259e342f43d7..fa5c557b5d9c6 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -14,7 +14,7 @@ doctest = false bitflags = "1.2.1" log = "0.4" rustc_ast = { path = "../librustc_ast" } -arena = { path = "../librustc_arena", package = "rustc_arena" } +rustc_arena = { path = "../librustc_arena" } rustc_middle = { path = "../librustc_middle" } rustc_ast_lowering = { path = "../librustc_ast_lowering" } rustc_ast_pretty = { path = "../librustc_ast_pretty" } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e5fc23e14d2ab..e67aef8f245f5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -19,6 +19,7 @@ pub use rustc_hir::def::{Namespace, PerNS}; use Determinacy::*; +use rustc_arena::TypedArena; use rustc_ast::ast::{self, FloatTy, IntTy, NodeId, UintTy}; use rustc_ast::ast::{Crate, CRATE_NODE_ID}; use rustc_ast::ast::{ItemKind, Path}; @@ -981,13 +982,13 @@ pub struct Resolver<'a> { /// Nothing really interesting here; it just provides memory for the rest of the crate. #[derive(Default)] pub struct ResolverArenas<'a> { - modules: arena::TypedArena>, + modules: TypedArena>, local_modules: RefCell>>, - name_bindings: arena::TypedArena>, - imports: arena::TypedArena>, - name_resolutions: arena::TypedArena>>, - macro_rules_bindings: arena::TypedArena>, - ast_paths: arena::TypedArena, + name_bindings: TypedArena>, + imports: TypedArena>, + name_resolutions: TypedArena>>, + macro_rules_bindings: TypedArena>, + ast_paths: TypedArena, } impl<'a> ResolverArenas<'a> { diff --git a/src/librustc_span/Cargo.toml b/src/librustc_span/Cargo.toml index 9cb0e54080aab..2a7a774872525 100644 --- a/src/librustc_span/Cargo.toml +++ b/src/librustc_span/Cargo.toml @@ -14,7 +14,7 @@ rustc_serialize = { path = "../librustc_serialize" } rustc_macros = { path = "../librustc_macros" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_index = { path = "../librustc_index" } -arena = { path = "../librustc_arena", package = "rustc_arena" } +rustc_arena = { path = "../librustc_arena" } scoped-tls = "1.0" unicode-width = "0.1.4" cfg-if = "0.1.2" diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 0f2d52c2264fd..d165409696eca 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -2,7 +2,7 @@ //! allows bidirectional lookup; i.e., given a value, one can easily find the //! type, and vice versa. -use arena::DroplessArena; +use rustc_arena::DroplessArena; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_macros::{symbols, HashStable_Generic}; diff --git a/src/librustc_trait_selection/Cargo.toml b/src/librustc_trait_selection/Cargo.toml index a1d984dcef0ff..fd11a85a9c406 100644 --- a/src/librustc_trait_selection/Cargo.toml +++ b/src/librustc_trait_selection/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -fmt_macros = { path = "../librustc_parse_format", package = "rustc_parse_format" } +rustc_parse_format = { path = "../librustc_parse_format" } log = { version = "0.4", features = ["release_max_level_info", "std"] } rustc_attr = { path = "../librustc_attr" } rustc_middle = { path = "../librustc_middle" } diff --git a/src/librustc_trait_selection/traits/on_unimplemented.rs b/src/librustc_trait_selection/traits/on_unimplemented.rs index 7e66e08f7e6a6..a1dfa838e7af3 100644 --- a/src/librustc_trait_selection/traits/on_unimplemented.rs +++ b/src/librustc_trait_selection/traits/on_unimplemented.rs @@ -1,11 +1,10 @@ -use fmt_macros::{ParseMode, Parser, Piece, Position}; - use rustc_ast::ast::{MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, ErrorReported}; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index b505b59806f35..9329069c48dd1 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -11,7 +11,7 @@ test = false doctest = false [dependencies] -arena = { path = "../librustc_arena", package = "rustc_arena" } +rustc_arena = { path = "../librustc_arena" } log = "0.4" rustc_middle = { path = "../librustc_middle" } rustc_attr = { path = "../librustc_attr" } diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 631f551ade4fe..23f4e1f5346e5 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -4,6 +4,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/variance.html use hir::Node; +use rustc_arena::TypedArena; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_middle::ty::query::Providers; @@ -31,7 +32,7 @@ pub fn provide(providers: &mut Providers<'_>) { fn crate_variances(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateVariancesMap<'_> { assert_eq!(crate_num, LOCAL_CRATE); - let mut arena = arena::TypedArena::default(); + let mut arena = TypedArena::default(); let terms_cx = terms::determine_parameters_to_be_inferred(tcx, &mut arena); let constraints_cx = constraints::add_constraints_from_crate(terms_cx); solve::solve_constraints(constraints_cx) diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index fe585826d2205..6e15485756d98 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -9,7 +9,7 @@ // `InferredIndex` is a newtype'd int representing the index of such // a variable. -use arena::TypedArena; +use rustc_arena::TypedArena; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::HirIdMap; diff --git a/src/test/run-make-fulldeps/save-analysis-fail/foo.rs b/src/test/run-make-fulldeps/save-analysis-fail/foo.rs index e042210ac79b0..5d504ced65e33 100644 --- a/src/test/run-make-fulldeps/save-analysis-fail/foo.rs +++ b/src/test/run-make-fulldeps/save-analysis-fail/foo.rs @@ -2,13 +2,13 @@ #![feature(box_syntax)] #![feature(rustc_private)] -extern crate graphviz; +extern crate rustc_graphviz; // A simple rust project extern crate krate2; extern crate krate2 as krate3; -use graphviz::RenderOption; +use rustc_graphviz::RenderOption; use std::collections::{HashMap,HashSet}; use std::cell::RefCell; use std::io::Write; diff --git a/src/test/run-make-fulldeps/save-analysis/foo.rs b/src/test/run-make-fulldeps/save-analysis/foo.rs index bc0209dc5832a..eb16ca93bf278 100644 --- a/src/test/run-make-fulldeps/save-analysis/foo.rs +++ b/src/test/run-make-fulldeps/save-analysis/foo.rs @@ -4,13 +4,13 @@ #![feature(associated_type_defaults)] #![feature(external_doc)] -extern crate graphviz; +extern crate rustc_graphviz; // A simple rust project extern crate krate2; extern crate krate2 as krate3; -use graphviz::RenderOption; +use rustc_graphviz::RenderOption; use std::collections::{HashMap,HashSet}; use std::cell::RefCell; use std::io::Write; diff --git a/src/test/ui-fulldeps/dropck-tarena-cycle-checked.rs b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.rs index a7e8131342f55..fabcd727482dc 100644 --- a/src/test/ui-fulldeps/dropck-tarena-cycle-checked.rs +++ b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.rs @@ -8,9 +8,9 @@ #![feature(rustc_private)] -extern crate arena; +extern crate rustc_arena; -use arena::TypedArena; +use rustc_arena::TypedArena; use std::cell::Cell; use id::Id; diff --git a/src/test/ui-fulldeps/dropck-tarena-unsound-drop.rs b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.rs index e454f44d1af6b..86485a9887fbe 100644 --- a/src/test/ui-fulldeps/dropck-tarena-unsound-drop.rs +++ b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.rs @@ -11,9 +11,9 @@ #![feature(rustc_private)] -extern crate arena; +extern crate rustc_arena; -use arena::TypedArena; +use rustc_arena::TypedArena; trait HasId { fn count(&self) -> usize; } diff --git a/src/test/ui-fulldeps/dropck_tarena_sound_drop.rs b/src/test/ui-fulldeps/dropck_tarena_sound_drop.rs index cf188d9efa3b2..c5b9efee8e730 100644 --- a/src/test/ui-fulldeps/dropck_tarena_sound_drop.rs +++ b/src/test/ui-fulldeps/dropck_tarena_sound_drop.rs @@ -12,9 +12,9 @@ #![allow(unstable)] #![feature(rustc_private)] -extern crate arena; +extern crate rustc_arena; -use arena::TypedArena; +use rustc_arena::TypedArena; trait HasId { fn count(&self) -> usize; } diff --git a/src/test/ui-fulldeps/regions-mock-tcx.rs b/src/test/ui-fulldeps/regions-mock-tcx.rs index 524c94a8555ec..30e6272324068 100644 --- a/src/test/ui-fulldeps/regions-mock-tcx.rs +++ b/src/test/ui-fulldeps/regions-mock-tcx.rs @@ -11,12 +11,12 @@ #![feature(rustc_private, libc)] -extern crate arena; +extern crate rustc_arena; extern crate libc; use TypeStructure::{TypeInt, TypeFunction}; use AstKind::{ExprInt, ExprVar, ExprLambda}; -use arena::TypedArena; +use rustc_arena::TypedArena; use std::collections::HashMap; use std::mem; diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index dfa6223f1b9dd..006503b546edf 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -352,7 +352,7 @@ impl Write { tts: &TokenStream, is_write: bool, ) -> (Option, Option) { - use fmt_macros::{ + use rustc_parse_format::{ AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, ParseMode, Parser, Piece, }; From d31d215c56ae4d163e77f8f5a59a4b49859b3d77 Mon Sep 17 00:00:00 2001 From: Patryk Wychowaniec Date: Tue, 2 Jun 2020 20:16:23 +0200 Subject: [PATCH 581/695] Improve E0433, so that it suggests missing imports --- src/librustc_resolve/diagnostics.rs | 11 +- src/librustc_resolve/late.rs | 146 ++++++++++++++---- src/librustc_resolve/lib.rs | 14 +- .../ui/derived-errors/issue-31997-1.stderr | 9 +- src/test/ui/error-codes/E0433.rs | 2 +- src/test/ui/error-codes/E0433.stderr | 6 +- .../ui/hygiene/no_implicit_prelude.stderr | 8 +- src/test/ui/resolve/use_suggestion.rs | 7 + src/test/ui/resolve/use_suggestion.stderr | 42 +++++ 9 files changed, 198 insertions(+), 47 deletions(-) create mode 100644 src/test/ui/resolve/use_suggestion.rs create mode 100644 src/test/ui/resolve/use_suggestion.stderr diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index ea237f1a04f99..cbb2878011c5f 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -1475,7 +1475,7 @@ crate fn show_candidates( // This is `None` if all placement locations are inside expansions use_placement_span: Option, candidates: &[ImportSuggestion], - better: bool, + instead: bool, found_use: bool, ) { if candidates.is_empty() { @@ -1486,6 +1486,7 @@ crate fn show_candidates( // by iterating through a hash map, so make sure they are ordered: let mut path_strings: Vec<_> = candidates.iter().map(|c| path_names_to_string(&c.path)).collect(); + path_strings.sort(); path_strings.dedup(); @@ -1494,8 +1495,9 @@ crate fn show_candidates( } else { ("one of these", "items") }; - let instead = if better { " instead" } else { "" }; - let msg = format!("consider importing {} {}{}", determiner, kind, instead); + + let instead = if instead { " instead" } else { "" }; + let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); if let Some(span) = use_placement_span { for candidate in &mut path_strings { @@ -1507,12 +1509,13 @@ crate fn show_candidates( err.span_suggestions(span, &msg, path_strings.into_iter(), Applicability::Unspecified); } else { - let mut msg = msg; msg.push(':'); + for candidate in path_strings { msg.push('\n'); msg.push_str(&candidate); } + err.note(&msg); } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 3b49b3b6ff7d2..f6728b758db65 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -29,8 +29,9 @@ use rustc_span::Span; use smallvec::{smallvec, SmallVec}; use log::debug; +use rustc_span::source_map::{respan, Spanned}; use std::collections::BTreeSet; -use std::mem::replace; +use std::mem::{replace, take}; mod diagnostics; crate mod lifetimes; @@ -234,6 +235,13 @@ impl<'a> PathSource<'a> { } } + fn is_call(self) -> bool { + match self { + PathSource::Expr(Some(&Expr { kind: ExprKind::Call(..), .. })) => true, + _ => false, + } + } + crate fn is_expected(self, res: Res) -> bool { match self { PathSource::Type => match res { @@ -1620,14 +1628,83 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let report_errors = |this: &mut Self, res: Option| { let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); + let def_id = this.parent_scope.module.normal_ancestor_id; - let better = res.is_some(); + let instead = res.is_some(); let suggestion = if res.is_none() { this.report_missing_type_error(path) } else { None }; - this.r.use_injections.push(UseError { err, candidates, def_id, better, suggestion }); + + this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion }); + PartialRes::new(Res::Err) }; + // For paths originating from calls (like in `HashMap::new()`), tries + // to enrich the plain `failed to resolve: ...` message with hints + // about possible missing imports. + // + // Similar thing, for types, happens in `report_errors` above. + let report_errors_for_call = |this: &mut Self, parent_err: Spanned>| { + if !source.is_call() { + return Some(parent_err); + } + + // Before we start looking for candidates, we have to get our hands + // on the type user is trying to perform invocation on; basically: + // we're transforming `HashMap::new` into just `HashMap` + let path = if let Some((_, path)) = path.split_last() { + path + } else { + return Some(parent_err); + }; + + let (mut err, candidates) = + this.smart_resolve_report_errors(path, span, PathSource::Type, None); + + if candidates.is_empty() { + err.cancel(); + return Some(parent_err); + } + + // There are two different error messages user might receive at + // this point: + // - E0412 cannot find type `{}` in this scope + // - E0433 failed to resolve: use of undeclared type or module `{}` + // + // The first one is emitted for paths in type-position, and the + // latter one - for paths in expression-position. + // + // Thus (since we're in expression-position at this point), not to + // confuse the user, we want to keep the *message* from E04322 (so + // `parent_err`), but we want *hints* from E0412 (so `err`). + // + // And that's what happens below - we're just mixing both messages + // into a single one. + let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); + + parent_err.cancel(); + + err.message = take(&mut parent_err.message); + err.code = take(&mut parent_err.code); + err.children = take(&mut parent_err.children); + + drop(parent_err); + + let def_id = this.parent_scope.module.normal_ancestor_id; + + this.r.use_injections.push(UseError { + err, + candidates, + def_id, + instead: false, + suggestion: None, + }); + + // We don't return `Some(parent_err)` here, because the error will + // be already printed as part of the `use` injections + None + }; + let partial_res = match self.resolve_qpath_anywhere( id, qself, @@ -1637,14 +1714,15 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source.defer_to_typeck(), crate_lint, ) { - Some(partial_res) if partial_res.unresolved_segments() == 0 => { + Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => { if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { partial_res } else { report_errors(self, Some(partial_res.base_res())) } } - Some(partial_res) if source.defer_to_typeck() => { + + Ok(Some(partial_res)) if source.defer_to_typeck() => { // Not fully resolved associated item `T::A::B` or `::A::B` // or `::A::B`. If `B` should be resolved in value namespace then // it needs to be added to the trait map. @@ -1655,25 +1733,34 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } let mut std_path = vec![Segment::from_ident(Ident::with_dummy_span(sym::std))]; + std_path.extend(path); + if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { - let cl = CrateLint::No; - let ns = Some(ns); if let PathResult::Module(_) | PathResult::NonModule(_) = - self.resolve_path(&std_path, ns, false, span, cl) + self.resolve_path(&std_path, Some(ns), false, span, CrateLint::No) { - // check if we wrote `str::from_utf8` instead of `std::str::from_utf8` + // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8` let item_span = path.iter().last().map(|segment| segment.ident.span).unwrap_or(span); - debug!("accessed item from `std` submodule as a bare type {:?}", std_path); + let mut hm = self.r.session.confused_type_with_std_module.borrow_mut(); hm.insert(item_span, span); - // In some places (E0223) we only have access to the full path hm.insert(span, span); } } + partial_res } + + Err(err) => { + if let Some(err) = report_errors_for_call(self, err) { + self.r.report_error(err.span, err.node); + } + + PartialRes::new(Res::Err) + } + _ => report_errors(self, None), }; @@ -1682,6 +1769,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Avoid recording definition of `A::B` in `::B::C`. self.r.record_partial_res(id, partial_res); } + partial_res } @@ -1711,17 +1799,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { span: Span, defer_to_typeck: bool, crate_lint: CrateLint, - ) -> Option { + ) -> Result, Spanned>> { let mut fin_res = None; + for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() { if i == 0 || ns != primary_ns { - match self.resolve_qpath(id, qself, path, ns, span, crate_lint) { - // If defer_to_typeck, then resolution > no resolution, - // otherwise full resolution > partial resolution > no resolution. + match self.resolve_qpath(id, qself, path, ns, span, crate_lint)? { Some(partial_res) if partial_res.unresolved_segments() == 0 || defer_to_typeck => { - return Some(partial_res); + return Ok(Some(partial_res)); } partial_res => { if fin_res.is_none() { @@ -1732,19 +1819,19 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - // `MacroNS` assert!(primary_ns != MacroNS); + if qself.is_none() { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span }; if let Ok((_, res)) = self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false) { - return Some(PartialRes::new(res)); + return Ok(Some(PartialRes::new(res))); } } - fin_res + Ok(fin_res) } /// Handles paths that may refer to associated items. @@ -1756,7 +1843,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ns: Namespace, span: Span, crate_lint: CrateLint, - ) -> Option { + ) -> Result, Spanned>> { debug!( "resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})", id, qself, path, ns, span, @@ -1767,10 +1854,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // This is a case like `::B`, where there is no // trait to resolve. In that case, we leave the `B` // segment to be resolved by type-check. - return Some(PartialRes::with_unresolved_segments( + return Ok(Some(PartialRes::with_unresolved_segments( Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len(), - )); + ))); } // Make sure `A::B` in `::C` is a trait item. @@ -1800,10 +1887,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // The remaining segments (the `C` in our example) will // have to be resolved by type-check, since that requires doing // trait resolution. - return Some(PartialRes::with_unresolved_segments( + return Ok(Some(PartialRes::with_unresolved_segments( partial_res.base_res(), partial_res.unresolved_segments() + path.len() - qself.position - 1, - )); + ))); } let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) { @@ -1838,11 +1925,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { PartialRes::new(module.res().unwrap()) } PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { - self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion }); - PartialRes::new(Res::Err) + return Err(respan(span, ResolutionError::FailedToResolve { label, suggestion })); } - PathResult::Module(..) | PathResult::Failed { .. } => return None, - PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), + PathResult::Module(..) | PathResult::Failed { .. } => return Ok(None), + PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"), }; if path.len() > 1 @@ -1862,7 +1948,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { PathResult::Module(ModuleOrUniformRoot::Module(module)) => { module.res().unwrap() } - _ => return Some(result), + _ => return Ok(Some(result)), } }; if result.base_res() == unqualified_result { @@ -1871,7 +1957,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - Some(result) + Ok(Some(result)) } fn with_resolved_label(&mut self, label: Option

for PathBuf { fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |p| self.push(p.as_ref())); } + + #[inline] + fn extend_one(&mut self, p: P) { + self.push(p.as_ref()); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index a98407da44850..a5ba3daba3e87 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -386,6 +386,17 @@ impl Extend for Wtf8Buf { self.bytes.reserve(low); iterator.for_each(move |code_point| self.push(code_point)); } + + #[inline] + fn extend_one(&mut self, code_point: CodePoint) { + self.push(code_point); + } + + #[inline] + fn extend_reserve(&mut self, additional: usize) { + // Lower bound of one byte per code point (ASCII only) + self.bytes.reserve(additional); + } } /// A borrowed slice of well-formed WTF-8 data. From e4345547b967a1fed4d62f6f0c539b56a2131aa4 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 26 May 2020 14:01:26 -0700 Subject: [PATCH 444/695] Use a canonical name for extend_reserve(additional) Co-authored-by: David Tolnay --- src/libcore/iter/traits/collect.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index da859db545d7e..4a90aca148547 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -352,7 +352,9 @@ pub trait Extend { /// /// The default implementation does nothing. #[unstable(feature = "extend_one", issue = "none")] - fn extend_reserve(&mut self, _additional: usize) {} + fn extend_reserve(&mut self, additional: usize) { + let _ = additional; + } } #[stable(feature = "extend_for_unit", since = "1.28.0")] From 10efaa37de8411272de3623ce50714d4860dc561 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 26 May 2020 14:03:34 -0700 Subject: [PATCH 445/695] Remove an old comment from HashMap::extend_reserve --- src/libstd/collections/hash/map.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a51f1998e4452..5ba5eff44076b 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2465,7 +2465,6 @@ where #[inline] fn extend_reserve(&mut self, additional: usize) { - // self.base.extend_reserve(additional); Extend::<(K, V)>::extend_reserve(self, additional) } } From a51b22a9fda2fff37b17ad7b7fa516b3385089a9 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 26 May 2020 14:15:29 -0700 Subject: [PATCH 446/695] Add extend_one tracking issue 72631 --- src/libcore/iter/traits/collect.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs index 4a90aca148547..9d20022b6ed6d 100644 --- a/src/libcore/iter/traits/collect.rs +++ b/src/libcore/iter/traits/collect.rs @@ -343,7 +343,7 @@ pub trait Extend { fn extend>(&mut self, iter: T); /// Extends a collection with exactly one element. - #[unstable(feature = "extend_one", issue = "none")] + #[unstable(feature = "extend_one", issue = "72631")] fn extend_one(&mut self, item: A) { self.extend(Some(item)); } @@ -351,7 +351,7 @@ pub trait Extend { /// Reserves capacity in a collection for the given number of additional elements. /// /// The default implementation does nothing. - #[unstable(feature = "extend_one", issue = "none")] + #[unstable(feature = "extend_one", issue = "72631")] fn extend_reserve(&mut self, additional: usize) { let _ = additional; } From 7242bda3dc6ad638392577fd43d1e30c3671ae74 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 30 May 2020 03:04:15 +0200 Subject: [PATCH 447/695] Be more careful around ty::Error in generators --- src/librustc_mir/transform/generator.rs | 69 +++++++++++++++---------- src/librustc_ty/needs_drop.rs | 10 +++- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 461b13c4f6382..60c040c25f97c 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -669,40 +669,33 @@ fn compute_storage_conflicts( storage_conflicts } -fn compute_layout<'tcx>( +/// Validates the typeck view of the generator against the actual set of types retained between +/// yield points. +fn sanitize_witness<'tcx>( tcx: TyCtxt<'tcx>, - source: MirSource<'tcx>, + body: &Body<'tcx>, + did: DefId, + witness: Ty<'tcx>, upvars: &Vec>, - interior: Ty<'tcx>, - always_live_locals: &storage::AlwaysLiveLocals, - movable: bool, - body: &mut Body<'tcx>, -) -> ( - FxHashMap, VariantIdx, usize)>, - GeneratorLayout<'tcx>, - IndexVec>>, + retained: &BitSet, ) { - // Use a liveness analysis to compute locals which are live across a suspension point - let LivenessInfo { - live_locals, - live_locals_at_suspension_points, - storage_conflicts, - storage_liveness, - } = locals_live_across_suspend_points(tcx, body, source, always_live_locals, movable); - - // Erase regions from the types passed in from typeck so we can compare them with - // MIR types let allowed_upvars = tcx.erase_regions(upvars); - let allowed = match interior.kind { + let allowed = match witness.kind { ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), - _ => bug!(), + _ => { + tcx.sess.delay_span_bug( + body.span, + &format!("unexpected generator witness type {:?}", witness.kind), + ); + return; + } }; - let param_env = tcx.param_env(source.def_id()); + let param_env = tcx.param_env(did); for (local, decl) in body.local_decls.iter_enumerated() { - // Ignore locals which are internal or not live - if !live_locals.contains(local) || decl.internal { + // Ignore locals which are internal or not retained between yields. + if !retained.contains(local) || decl.internal { continue; } let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty); @@ -715,10 +708,34 @@ fn compute_layout<'tcx>( "Broken MIR: generator contains type {} in MIR, \ but typeck only knows about {}", decl.ty, - interior + witness, ); } } +} + +fn compute_layout<'tcx>( + tcx: TyCtxt<'tcx>, + source: MirSource<'tcx>, + upvars: &Vec>, + interior: Ty<'tcx>, + always_live_locals: &storage::AlwaysLiveLocals, + movable: bool, + body: &mut Body<'tcx>, +) -> ( + FxHashMap, VariantIdx, usize)>, + GeneratorLayout<'tcx>, + IndexVec>>, +) { + // Use a liveness analysis to compute locals which are live across a suspension point + let LivenessInfo { + live_locals, + live_locals_at_suspension_points, + storage_conflicts, + storage_liveness, + } = locals_live_across_suspend_points(tcx, body, source, always_live_locals, movable); + + sanitize_witness(tcx, body, source.def_id(), interior, upvars, &live_locals); // Gather live local types and their indices. let mut locals = IndexVec::::new(); diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs index 1b059fa3dbdf0..ca5477ef4a986 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/src/librustc_ty/needs_drop.rs @@ -98,7 +98,7 @@ where } } - ty::Generator(_, substs, _) => { + ty::Generator(def_id, substs, _) => { let substs = substs.as_generator(); for upvar_ty in substs.upvar_tys() { queue_type(self, upvar_ty); @@ -107,7 +107,13 @@ where let witness = substs.witness(); let interior_tys = match &witness.kind { ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), - _ => bug!(), + _ => { + tcx.sess.delay_span_bug( + tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP), + &format!("unexpected generator witness type {:?}", witness), + ); + return Some(Err(AlwaysRequiresDrop)); + } }; for interior_ty in interior_tys { From 905d738b1af874e248b9fe7fe4b115458975d401 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 29 May 2020 11:47:17 -0400 Subject: [PATCH 448/695] `StableSourceFileId::new_from_pieces` does not need to be public. (and I want to discourage further use of it if possible.) --- src/librustc_span/source_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs index 51f5541766305..dc85f7990b92c 100644 --- a/src/librustc_span/source_map.rs +++ b/src/librustc_span/source_map.rs @@ -95,7 +95,7 @@ impl StableSourceFileId { ) } - pub fn new_from_pieces( + fn new_from_pieces( name: &FileName, name_was_remapped: bool, unmapped_path: Option<&FileName>, From da09fd3db0c71680e16311140d07e8f1e079af82 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 29 May 2020 11:31:55 -0400 Subject: [PATCH 449/695] Split payload of FileName::Real to track both real and virutalized paths. Such splits arise from metadata refs into libstd. This way, we can (in a follow on commit) continue to emit the virtual name into things like the like the StableSourceFileId that ends up in incremetnal build artifacts, while still using the devirtualized file path when we want to access the file. Note that this commit is intended to be a refactoring; the actual fix to the bug in question is in a follow-on commit. --- src/librustc_expand/base.rs | 2 +- src/librustc_expand/expand.rs | 2 +- src/librustc_expand/module.rs | 5 ++- src/librustc_expand/proc_macro_server.rs | 3 +- src/librustc_interface/passes.rs | 11 ++++-- src/librustc_metadata/rmeta/decoder.rs | 25 +++++++----- src/librustc_metadata/rmeta/encoder.rs | 1 + src/librustc_save_analysis/span_utils.rs | 5 ++- src/librustc_span/lib.rs | 48 ++++++++++++++++++++++-- src/librustc_span/source_map.rs | 25 ++++++++---- src/librustdoc/html/render.rs | 5 ++- src/librustdoc/html/render/cache.rs | 2 +- src/librustdoc/html/sources.rs | 4 +- src/librustdoc/test.rs | 4 +- 14 files changed, 103 insertions(+), 39 deletions(-) diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 649aac488fcb3..3a06770e31bd8 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -1095,7 +1095,7 @@ impl<'a> ExtCtxt<'a> { if !path.is_absolute() { let callsite = span.source_callsite(); let mut result = match self.source_map().span_to_unmapped_path(callsite) { - FileName::Real(path) => path, + FileName::Real(name) => name.into_local_path(), FileName::DocTest(path, _) => path, other => { return Err(self.struct_span_err( diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index b505302f62501..25b94ff2cbeb1 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -340,7 +340,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let mut module = ModuleData { mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)], directory: match self.cx.source_map().span_to_unmapped_path(krate.span) { - FileName::Real(path) => path, + FileName::Real(name) => name.into_local_path(), other => PathBuf::from(other.to_string()), }, }; diff --git a/src/librustc_expand/module.rs b/src/librustc_expand/module.rs index 9bb2b57b7f591..82215c7297ed6 100644 --- a/src/librustc_expand/module.rs +++ b/src/librustc_expand/module.rs @@ -71,7 +71,7 @@ crate fn parse_external_mod( // Extract the directory path for submodules of `module`. let path = sess.source_map().span_to_unmapped_path(module.inner); let mut path = match path { - FileName::Real(path) => path, + FileName::Real(name) => name.into_local_path(), other => PathBuf::from(other.to_string()), }; path.pop(); @@ -189,7 +189,8 @@ fn error_cannot_declare_mod_here<'a, T>( let mut err = sess.span_diagnostic.struct_span_err(span, "cannot declare a new module at this location"); if !span.is_dummy() { - if let FileName::Real(src_path) = sess.source_map().span_to_filename(span) { + if let FileName::Real(src_name) = sess.source_map().span_to_filename(span) { + let src_path = src_name.into_local_path(); if let Some(stem) = src_path.file_stem() { let mut dest_path = src_path.clone(); dest_path.set_file_name(stem); diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index b9693c2c86278..36af83711f7e4 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -602,7 +602,8 @@ impl server::SourceFile for Rustc<'_> { } fn path(&mut self, file: &Self::SourceFile) -> String { match file.name { - FileName::Real(ref path) => path + FileName::Real(ref name) => name + .local_path() .to_str() .expect("non-UTF8 file path in `proc_macro::SourceFile::path`") .to_string(), diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 214701db724ec..9f1f38efb484b 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -33,7 +33,7 @@ use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_span::FileName; +use rustc_span::{FileName, RealFileName}; use rustc_trait_selection::traits; use rustc_typeck as typeck; @@ -569,13 +569,16 @@ fn write_out_deps( for cnum in resolver.cstore().crates_untracked() { let source = resolver.cstore().crate_source_untracked(cnum); if let Some((path, _)) = source.dylib { - files.push(escape_dep_filename(&FileName::Real(path))); + let file_name = FileName::Real(RealFileName::Named(path)); + files.push(escape_dep_filename(&file_name)); } if let Some((path, _)) = source.rlib { - files.push(escape_dep_filename(&FileName::Real(path))); + let file_name = FileName::Real(RealFileName::Named(path)); + files.push(escape_dep_filename(&file_name)); } if let Some((path, _)) = source.rmeta { - files.push(escape_dep_filename(&FileName::Real(path))); + let file_name = FileName::Real(RealFileName::Named(path)); + files.push(escape_dep_filename(&file_name)); } } }); diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 2b292b35c159d..f5a9dceb78295 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -1471,15 +1471,22 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { if let Some(virtual_dir) = virtual_rust_source_base_dir { if let Some(real_dir) = &sess.real_rust_source_base_dir { - if let rustc_span::FileName::Real(path) = name { - if let Ok(rest) = path.strip_prefix(virtual_dir) { - let new_path = real_dir.join(rest); - debug!( - "try_to_translate_virtual_to_real: `{}` -> `{}`", - path.display(), - new_path.display(), - ); - *path = new_path; + if let rustc_span::FileName::Real(old_name) = name { + if let rustc_span::RealFileName::Named(one_path) = old_name { + if let Ok(rest) = one_path.strip_prefix(virtual_dir) { + let virtual_name = one_path.clone(); + let new_path = real_dir.join(rest); + debug!( + "try_to_translate_virtual_to_real: `{}` -> `{}`", + virtual_name.display(), + new_path.display(), + ); + let new_name = rustc_span::RealFileName::Devirtualized { + local_path: new_path, + virtual_name, + }; + *old_name = new_name; + } } } } diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 91fbfcc0133eb..b47a166feb522 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -396,6 +396,7 @@ impl<'tcx> EncodeContext<'tcx> { // any relative paths are potentially relative to a // wrong directory. FileName::Real(ref name) => { + let name = name.local_path(); let mut adapted = (**source_file).clone(); adapted.name = Path::new(&working_dir).join(name).into(); adapted.name_hash = { diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 6620941c44046..d5f992b0de05d 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -16,12 +16,13 @@ impl<'a> SpanUtils<'a> { pub fn make_filename_string(&self, file: &SourceFile) -> String { match &file.name { - FileName::Real(path) if !file.name_was_remapped => { + FileName::Real(name) if !file.name_was_remapped => { + let path = name.local_path(); if path.is_absolute() { self.sess .source_map() .path_mapping() - .map_prefix(path.clone()) + .map_prefix(path.into()) .0 .display() .to_string() diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 58cdb87158afe..f18a863d7208e 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -53,7 +53,7 @@ use std::cmp::{self, Ordering}; use std::fmt; use std::hash::Hash; use std::ops::{Add, Sub}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::str::FromStr; use md5::Md5; @@ -81,11 +81,45 @@ impl Globals { scoped_tls::scoped_thread_local!(pub static GLOBALS: Globals); +/// FIXME: Perhaps this should not implement Rustc{Decodable, Encodable} +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, RustcDecodable, RustcEncodable)] +#[derive(HashStable_Generic)] +pub enum RealFileName { + Named(PathBuf), + /// For de-virtualized paths (namely paths into libstd that have been mapped + /// to the appropriate spot on the local host's file system), + Devirtualized { + /// `local_path` is the (host-dependent) local path to the file. + local_path: PathBuf, + /// `virtual_name` is the stable path rustc will store internally within + /// build artifacts. + virtual_name: PathBuf, + }, +} + +impl RealFileName { + /// Returns the path suitable for reading from the file system on the local host. + pub fn local_path(&self) -> &Path { + match self { + RealFileName::Named(p) + | RealFileName::Devirtualized { local_path: p, virtual_name: _ } => &p, + } + } + + /// Returns the path suitable for reading from the file system on the local host. + pub fn into_local_path(self) -> PathBuf { + match self { + RealFileName::Named(p) + | RealFileName::Devirtualized { local_path: p, virtual_name: _ } => p, + } + } +} + /// Differentiates between real files and common virtual files. #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, RustcDecodable, RustcEncodable)] #[derive(HashStable_Generic)] pub enum FileName { - Real(PathBuf), + Real(RealFileName), /// Call to `quote!`. QuoteExpansion(u64), /// Command line. @@ -107,7 +141,13 @@ impl std::fmt::Display for FileName { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use FileName::*; match *self { - Real(ref path) => write!(fmt, "{}", path.display()), + Real(RealFileName::Named(ref path)) => write!(fmt, "{}", path.display()), + // FIXME: might be nice to display both compoments of Devirtualized. + // But for now (to backport fix for issue #70924), best to not + // perturb diagnostics so its obvious test suite still works. + Real(RealFileName::Devirtualized { ref local_path, virtual_name: _ }) => { + write!(fmt, "{}", local_path.display()) + } QuoteExpansion(_) => write!(fmt, ""), MacroExpansion(_) => write!(fmt, ""), Anon(_) => write!(fmt, ""), @@ -123,7 +163,7 @@ impl std::fmt::Display for FileName { impl From for FileName { fn from(p: PathBuf) -> Self { assert!(!p.to_string_lossy().ends_with('>')); - FileName::Real(p) + FileName::Real(RealFileName::Named(p)) } } diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs index dc85f7990b92c..c432de3e847cb 100644 --- a/src/librustc_span/source_map.rs +++ b/src/librustc_span/source_map.rs @@ -235,7 +235,7 @@ impl SourceMap { fn try_new_source_file( &self, - filename: FileName, + mut filename: FileName, src: String, ) -> Result, OffsetOverflowError> { // The path is used to determine the directory for loading submodules and @@ -245,13 +245,22 @@ impl SourceMap { // be empty, so the working directory will be used. let unmapped_path = filename.clone(); - let (filename, was_remapped) = match filename { - FileName::Real(filename) => { - let (filename, was_remapped) = self.path_mapping.map_prefix(filename); - (FileName::Real(filename), was_remapped) + let was_remapped; + if let FileName::Real(real_filename) = &mut filename { + match real_filename { + RealFileName::Named(path_to_be_remapped) + | RealFileName::Devirtualized { + local_path: path_to_be_remapped, + virtual_name: _, + } => { + let mapped = self.path_mapping.map_prefix(path_to_be_remapped.clone()); + was_remapped = mapped.1; + *path_to_be_remapped = mapped.0; + } } - other => (other, false), - }; + } else { + was_remapped = false; + } let file_id = StableSourceFileId::new_from_pieces(&filename, was_remapped, Some(&unmapped_path)); @@ -998,7 +1007,7 @@ impl SourceMap { } pub fn ensure_source_file_source_present(&self, source_file: Lrc) -> bool { source_file.add_external_src(|| match source_file.name { - FileName::Real(ref name) => self.file_loader.read_file(name).ok(), + FileName::Real(ref name) => self.file_loader.read_file(name.local_path()).ok(), _ => None, }) } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index cd49da88d9652..f6fb10b018094 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -473,7 +473,7 @@ pub fn run( } = options; let src_root = match krate.src { - FileName::Real(ref p) => match p.parent() { + FileName::Real(ref p) => match p.local_path().parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), }, @@ -1621,9 +1621,10 @@ impl Context { // We can safely ignore synthetic `SourceFile`s. let file = match item.source.filename { - FileName::Real(ref path) => path, + FileName::Real(ref path) => path.local_path().to_path_buf(), _ => return None, }; + let file = &file; let (krate, path) = if item.source.cnum == LOCAL_CRATE { if let Some(path) = self.shared.local_sources.get(file) { diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 57d385de32096..225940773413e 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -173,7 +173,7 @@ impl Cache { // Cache where all our extern crates are located for &(n, ref e) in &krate.externs { let src_root = match e.src { - FileName::Real(ref p) => match p.parent() { + FileName::Real(ref p) => match p.local_path().parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), }, diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index c5f44baced2e4..018c0e82c4561 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -67,10 +67,10 @@ impl<'a> SourceCollector<'a> { /// Renders the given filename into its corresponding HTML source file. fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> { let p = match *filename { - FileName::Real(ref file) => file, + FileName::Real(ref file) => file.local_path().to_path_buf(), _ => return Ok(()), }; - if self.scx.local_sources.contains_key(&**p) { + if self.scx.local_sources.contains_key(&*p) { // We've already emitted this source return Ok(()); } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 284e6d421ee2f..ad7f2c112c151 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -688,7 +688,7 @@ impl Collector { let filename = source_map.span_to_filename(self.position); if let FileName::Real(ref filename) = filename { if let Ok(cur_dir) = env::current_dir() { - if let Ok(path) = filename.strip_prefix(&cur_dir) { + if let Ok(path) = filename.local_path().strip_prefix(&cur_dir) { return path.to_owned().into(); } } @@ -718,7 +718,7 @@ impl Tester for Collector { // FIXME(#44940): if doctests ever support path remapping, then this filename // needs to be the result of `SourceMap::span_to_unmapped_path`. let path = match &filename { - FileName::Real(path) => path.clone(), + FileName::Real(path) => path.local_path().to_path_buf(), _ => PathBuf::from(r"doctest.rs"), }; From 5e5a3d58678d70ad49b87251a12d11dea52e69b0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 29 May 2020 14:04:03 -0400 Subject: [PATCH 450/695] Use the virtual name for libstd files in StableSourceFileId and also in the encoded build artifacts. Fix #70924. --- src/librustc_metadata/rmeta/encoder.rs | 2 +- src/librustc_span/lib.rs | 13 +++++++++++++ src/librustc_span/source_map.rs | 11 ++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index b47a166feb522..9964c9c94c951 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -396,7 +396,7 @@ impl<'tcx> EncodeContext<'tcx> { // any relative paths are potentially relative to a // wrong directory. FileName::Real(ref name) => { - let name = name.local_path(); + let name = name.stable_name(); let mut adapted = (**source_file).clone(); adapted.name = Path::new(&working_dir).join(name).into(); adapted.name_hash = { diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index f18a863d7208e..e17fe1fa782cb 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -99,6 +99,7 @@ pub enum RealFileName { impl RealFileName { /// Returns the path suitable for reading from the file system on the local host. + /// Avoid embedding this in build artifacts; see `stable_name` for that. pub fn local_path(&self) -> &Path { match self { RealFileName::Named(p) @@ -107,12 +108,24 @@ impl RealFileName { } /// Returns the path suitable for reading from the file system on the local host. + /// Avoid embedding this in build artifacts; see `stable_name` for that. pub fn into_local_path(self) -> PathBuf { match self { RealFileName::Named(p) | RealFileName::Devirtualized { local_path: p, virtual_name: _ } => p, } } + + /// Returns the path suitable for embedding into build artifacts. Note that + /// a virtualized path will not correspond to a valid file system path; see + /// `local_path` for something that is more likely to return paths into the + /// local host file system. + pub fn stable_name(&self) -> &Path { + match self { + RealFileName::Named(p) + | RealFileName::Devirtualized { local_path: _, virtual_name: p } => &p, + } + } } /// Differentiates between real files and common virtual files. diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs index c432de3e847cb..c33c1dd29cb72 100644 --- a/src/librustc_span/source_map.rs +++ b/src/librustc_span/source_map.rs @@ -86,6 +86,8 @@ impl FileLoader for RealFileLoader { #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub struct StableSourceFileId(u128); +// FIXME: we need a more globally consistent approach to the problem solved by +// StableSourceFileId, perhaps built atop source_file.name_hash. impl StableSourceFileId { pub fn new(source_file: &SourceFile) -> StableSourceFileId { StableSourceFileId::new_from_pieces( @@ -102,7 +104,14 @@ impl StableSourceFileId { ) -> StableSourceFileId { let mut hasher = StableHasher::new(); - name.hash(&mut hasher); + if let FileName::Real(real_name) = name { + // rust-lang/rust#70924: Use the stable (virtualized) name when + // available. (We do not want artifacts from transient file system + // paths for libstd to leak into our build artifacts.) + real_name.stable_name().hash(&mut hasher) + } else { + name.hash(&mut hasher); + } name_was_remapped.hash(&mut hasher); unmapped_path.hash(&mut hasher); From f8d38057335ff6c760fabb53b62d87938d8fb17f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 09:33:05 +0200 Subject: [PATCH 451/695] miri validation: clarify valid values of 'char' --- src/librustc_mir/interpret/validity.rs | 2 +- src/test/ui/consts/const-eval/ub-enum.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index c83555d65faf0..f2ce46e9740f9 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -485,7 +485,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' try_validation!( value.to_char(), self.path, - err_ub!(InvalidChar(..)) => { "{}", value } expected { "a valid unicode codepoint" }, + err_ub!(InvalidChar(..)) => { "{}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" }, ); Ok(true) } diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index d8dafac3e70a1..e49fd3e0b970b 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -82,7 +82,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:87:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0xffffffff at ..0.1, but expected a valid unicode codepoint + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0xffffffff at ..0.1, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. From 8ef93928282c939554b9b7b518665fcde06c6ba6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 11:41:58 +0200 Subject: [PATCH 452/695] multiple Return terminators are possible --- src/librustc_middle/mir/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 20c64d40fabbd..0e9c133e2c322 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -1072,7 +1072,8 @@ pub enum TerminatorKind<'tcx> { Abort, /// Indicates a normal return. The return place should have - /// been filled in by now. This should occur at most once. + /// been filled in before this executes. This can occur multiple times + /// in different basic blocks. Return, /// Indicates a terminator that can never be reached. From 77503578e1e727228ce47dd7847302936cf80a23 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 30 May 2020 18:48:54 +0900 Subject: [PATCH 453/695] Return early to avoid ICE --- .../traits/error_reporting/suggestions.rs | 6 ++++++ src/librustc_trait_selection/traits/mod.rs | 7 ------- src/test/ui/suggestions/issue-72766.rs | 20 +++++++++++++++++++ src/test/ui/suggestions/issue-72766.stderr | 15 ++++++++++++++ .../clippy/clippy_lints/src/utils/mod.rs | 5 +++++ 5 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/suggestions/issue-72766.rs create mode 100644 src/test/ui/suggestions/issue-72766.stderr diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 31992f298080e..3174f43c65792 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1909,6 +1909,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); + // Do not check on infer_types to avoid panic in evaluate_obligation. + if self_ty.has_infer_types() { + return; + } + let self_ty = self.tcx.erase_regions(&self_ty); + let impls_future = self.tcx.type_implements_trait(( future_trait, self_ty, diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index b45de72ab0262..958ba69a8262c 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -540,13 +540,6 @@ fn type_implements_trait<'tcx>( trait_def_id, ty, params, param_env ); - // Do not check on infer_types to avoid panic in evaluate_obligation. - if ty.has_infer_types() { - return false; - } - - let ty = tcx.erase_regions(&ty); - let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) }; let obligation = Obligation { diff --git a/src/test/ui/suggestions/issue-72766.rs b/src/test/ui/suggestions/issue-72766.rs new file mode 100644 index 0000000000000..0448f0719589d --- /dev/null +++ b/src/test/ui/suggestions/issue-72766.rs @@ -0,0 +1,20 @@ +// edition:2018 +// compile-flags: -Cincremental=tmp/issue-72766 + +pub struct SadGirl; + +impl SadGirl { + pub async fn call(&self) -> Result<(), ()> { + Ok(()) + } +} + +async fn async_main() -> Result<(), ()> { + // should be `.call().await?` + SadGirl {}.call()?; //~ ERROR: the `?` operator can only be applied to values + Ok(()) +} + +fn main() { + let _ = async_main(); +} diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr new file mode 100644 index 0000000000000..4290f3b4bf1aa --- /dev/null +++ b/src/test/ui/suggestions/issue-72766.stderr @@ -0,0 +1,15 @@ +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/issue-72766.rs:14:5 + | +LL | SadGirl {}.call()?; + | ^^^^^^^^^^^^^^^^^^ + | | + | the `?` operator cannot be applied to type `impl std::future::Future` + | help: consider using `.await` here: `SadGirl {}.call().await?` + | + = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` + = note: required by `std::ops::Try::into_result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 6c1488664bf00..6dd8fef7e82da 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -323,6 +323,11 @@ pub fn implements_trait<'a, 'tcx>( trait_id: DefId, ty_params: &[GenericArg<'tcx>], ) -> bool { + // Do not check on infer_types to avoid panic in evaluate_obligation. + if ty.has_infer_types() { + return false; + } + let ty = cx.tcx.erase_regions(&ty); let ty_params = cx.tcx.mk_substs(ty_params.iter()); cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } From 9fd8e1088fe858b6a5da2b7e8baaeeacd26c6a31 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sat, 30 May 2020 18:48:54 +0900 Subject: [PATCH 454/695] Return early to avoid ICE --- clippy_lints/src/utils/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 6c1488664bf00..6dd8fef7e82da 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -323,6 +323,11 @@ pub fn implements_trait<'a, 'tcx>( trait_id: DefId, ty_params: &[GenericArg<'tcx>], ) -> bool { + // Do not check on infer_types to avoid panic in evaluate_obligation. + if ty.has_infer_types() { + return false; + } + let ty = cx.tcx.erase_regions(&ty); let ty_params = cx.tcx.mk_substs(ty_params.iter()); cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } From 72d85db6eea29004a467842923c07169bc304217 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 11:49:31 +0200 Subject: [PATCH 455/695] expose char::encode_utf8_raw for libstd --- src/libcore/char/methods.rs | 99 ++++++++++++++++++++++--------------- src/libcore/char/mod.rs | 4 ++ 2 files changed, 63 insertions(+), 40 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 5c5bc9adb5df2..112e7e38e414b 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -593,16 +593,7 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len_utf8(self) -> usize { - let code = self as u32; - if code < MAX_ONE_B { - 1 - } else if code < MAX_TWO_B { - 2 - } else if code < MAX_THREE_B { - 3 - } else { - 4 - } + len_utf8(self as u32) } /// Returns the number of 16-bit code units this `char` would need if @@ -670,36 +661,7 @@ impl char { #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - let code = self as u32; - let len = self.len_utf8(); - match (len, &mut dst[..]) { - (1, [a, ..]) => { - *a = code as u8; - } - (2, [a, b, ..]) => { - *a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *b = (code & 0x3F) as u8 | TAG_CONT; - } - (3, [a, b, c, ..]) => { - *a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *b = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *c = (code & 0x3F) as u8 | TAG_CONT; - } - (4, [a, b, c, d, ..]) => { - *a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *b = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *c = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *d = (code & 0x3F) as u8 | TAG_CONT; - } - _ => panic!( - "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", - len, - code, - dst.len(), - ), - }; - // SAFETY: We just wrote UTF-8 content in, so converting to str is fine. - unsafe { from_utf8_unchecked_mut(&mut dst[..len]) } + encode_utf8_raw(self as u32, dst) } /// Encodes this character as UTF-16 into the provided `u16` buffer, @@ -1673,3 +1635,60 @@ impl char { } } } + +#[inline] +fn len_utf8(code: u32) -> usize { + if code < MAX_ONE_B { + 1 + } else if code < MAX_TWO_B { + 2 + } else if code < MAX_THREE_B { + 3 + } else { + 4 + } +} + +/// Encodes a raw u32 value as UTF-8 into the provided byte buffer, +/// and then returns the subslice of the buffer that contains the encoded character. +/// +/// Unlike `char::encode_utf8`, this method can be called on codepoints in the surrogate range. +/// +/// # Panics +/// +/// Panics if the buffer is not large enough. +/// A buffer of length four is large enough to encode any `char`. +#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] +#[doc(hidden)] +#[inline] +pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut str { + let len = len_utf8(code); + match (len, &mut dst[..]) { + (1, [a, ..]) => { + *a = code as u8; + } + (2, [a, b, ..]) => { + *a = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *b = (code & 0x3F) as u8 | TAG_CONT; + } + (3, [a, b, c, ..]) => { + *a = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *b = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *c = (code & 0x3F) as u8 | TAG_CONT; + } + (4, [a, b, c, d, ..]) => { + *a = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *b = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *c = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *d = (code & 0x3F) as u8 | TAG_CONT; + } + _ => panic!( + "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", + len, + code, + dst.len(), + ), + }; + // SAFETY: We just wrote UTF-8 content in, so converting to str is fine. + unsafe { from_utf8_unchecked_mut(&mut dst[..len]) } +} diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index bf65c31e13597..40b429b749668 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -37,6 +37,10 @@ pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; #[stable(feature = "unicode_version", since = "1.45.0")] pub use crate::unicode::UNICODE_VERSION; +// perma-unstable re-exports +#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] +pub use self::methods::encode_utf8_raw; + use crate::fmt::{self, Write}; use crate::iter::FusedIterator; From 3182cdf9baf8ed9e8ae24f4742ee5d3d01c2b54a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 11:53:50 +0200 Subject: [PATCH 456/695] wtf8: use encode_utf8_raw --- src/libstd/lib.rs | 1 + src/libstd/sys_common/wtf8.rs | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index cc3e613fa3d60..3e3c1fd9026bc 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -247,6 +247,7 @@ #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] +#![feature(char_internals)] #![feature(clamp)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index a98407da44850..90bbf4afd1a32 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -201,9 +201,8 @@ impl Wtf8Buf { /// Copied from String::push /// This does **not** include the WTF-8 concatenation check. fn push_code_point_unchecked(&mut self, code_point: CodePoint) { - let c = unsafe { char::from_u32_unchecked(code_point.value) }; let mut bytes = [0; 4]; - let bytes = c.encode_utf8(&mut bytes).as_bytes(); + let bytes = char::encode_utf8_raw(code_point.value, &mut bytes).as_bytes(); self.bytes.extend_from_slice(bytes) } From 9c627c33dde998cfe42bcde07e1c5692370daf63 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 12:08:55 +0200 Subject: [PATCH 457/695] also expose and use encode_utf16_raw for wtf8 --- src/libcore/char/methods.rs | 59 ++++++++++++++++++++++------------- src/libcore/char/mod.rs | 2 ++ src/libstd/sys_common/wtf8.rs | 3 +- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 112e7e38e414b..b1b3c70efb1c7 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -701,28 +701,7 @@ impl char { #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - let mut code = self as u32; - // SAFETY: each arm checks whether there are enough bits to write into - unsafe { - if (code & 0xFFFF) == code && !dst.is_empty() { - // The BMP falls through (assuming non-surrogate, as it should) - *dst.get_unchecked_mut(0) = code as u16; - slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) - } else if dst.len() >= 2 { - // Supplementary planes break into surrogates. - code -= 0x1_0000; - *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); - *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); - slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) - } else { - panic!( - "encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf16(), - code, - dst.len(), - ) - } - } + encode_utf16_raw(self as u32, dst) } /// Returns `true` if this `char` has the `Alphabetic` property. @@ -1692,3 +1671,39 @@ pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut str { // SAFETY: We just wrote UTF-8 content in, so converting to str is fine. unsafe { from_utf8_unchecked_mut(&mut dst[..len]) } } + +/// Encodes a raw u32 value as UTF-16 into the provided `u16` buffer, +/// and then returns the subslice of the buffer that contains the encoded character. +/// +/// Unlike `char::encode_utf16`, this method can be called on codepoints in the surrogate range. +/// +/// # Panics +/// +/// Panics if the buffer is not large enough. +/// A buffer of length 2 is large enough to encode any `char`. +#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] +#[doc(hidden)] +#[inline] +pub fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] { + // SAFETY: each arm checks whether there are enough bits to write into + unsafe { + if (code & 0xFFFF) == code && !dst.is_empty() { + // The BMP falls through (assuming non-surrogate, as it should) + *dst.get_unchecked_mut(0) = code as u16; + slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) + } else if dst.len() >= 2 { + // Supplementary planes break into surrogates. + code -= 0x1_0000; + *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); + *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); + slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) + } else { + panic!( + "encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf16(), + code, + dst.len(), + ) + } + } +} diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 40b429b749668..1b4e906e4e475 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -39,6 +39,8 @@ pub use crate::unicode::UNICODE_VERSION; // perma-unstable re-exports #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] +pub use self::methods::encode_utf16_raw; +#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf8_raw; use crate::fmt::{self, Write}; diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 90bbf4afd1a32..9f589c93ae59c 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -828,8 +828,7 @@ impl<'a> Iterator for EncodeWide<'a> { let mut buf = [0; 2]; self.code_points.next().map(|code_point| { - let c = unsafe { char::from_u32_unchecked(code_point.value) }; - let n = c.encode_utf16(&mut buf).len(); + let n = char::encode_utf16_raw(code_point.value, &mut buf).len(); if n == 2 { self.extra = buf[1]; } From 49b1b4c438a87f54ebbae90b9b21ccce7622f8e7 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 17 May 2020 17:02:57 +0200 Subject: [PATCH 458/695] more `LocalDefId`s --- src/librustc_interface/passes.rs | 2 +- src/librustc_middle/query/mod.rs | 10 ++++++++-- src/librustc_mir/transform/check_unsafety.rs | 17 +++++++++-------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 214701db724ec..c06fd91133b5c 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -838,7 +838,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { sess.time("MIR_effect_checking", || { for def_id in tcx.body_owners() { - mir::transform::check_unsafety::check_unsafety(tcx, def_id.to_def_id()) + mir::transform::check_unsafety::check_unsafety(tcx, def_id) } }); diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 85451bf6538e4..59b6f5e529baa 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -386,8 +386,14 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) } - /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error - query unsafe_derive_on_repr_packed(_: DefId) -> () {} + /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error. + /// + /// Unsafety checking is executed for each method separately, but we only want + /// to emit this error once per derive. As there are some impls with multiple + /// methods, we use a query for deduplication. + query unsafe_derive_on_repr_packed(key: LocalDefId) -> () { + desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) } + } /// The signature of functions and closures. query fn_sig(_: DefId) -> ty::PolyFnSig<'tcx> {} diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 1f01bc0e19513..e32bccc85ee6f 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -579,8 +579,8 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckRe } } -fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: DefId) { - let lint_hir_id = tcx.hir().as_local_hir_id(def_id.expect_local()); +fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let lint_hir_id = tcx.hir().as_local_hir_id(def_id); tcx.struct_span_lint_hir(SAFE_PACKED_BORROWS, lint_hir_id, tcx.def_span(def_id), |lint| { // FIXME: when we make this a hard error, this should have its @@ -659,16 +659,15 @@ fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option { } } -pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { +pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { debug!("check_unsafety({:?})", def_id); // closures are handled by their parent fn. - if tcx.is_closure(def_id) { + if tcx.is_closure(def_id.to_def_id()) { return; } - let UnsafetyCheckResult { violations, unsafe_blocks } = - tcx.unsafety_check_result(def_id.expect_local()); + let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id); for &UnsafetyViolation { source_info, lint_root, description, details, kind } in violations.iter() @@ -693,8 +692,10 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { .emit(); } UnsafetyViolationKind::BorrowPacked => { - if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) { - tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id); + if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id.to_def_id()) { + // If a method is defined in the local crate, + // the impl containing that method should also be. + tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); } else { tcx.struct_span_lint_hir( SAFE_PACKED_BORROWS, From 0aa7f4d2f2ff55b8cfe5de5e4e7665a8fdeaf050 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 2 May 2020 21:44:25 +0200 Subject: [PATCH 459/695] Make TLS accesses explicit in MIR --- src/librustc_codegen_llvm/common.rs | 1 + src/librustc_codegen_ssa/mir/rvalue.rs | 8 ++++ src/librustc_middle/mir/interpret/error.rs | 3 ++ src/librustc_middle/mir/interpret/mod.rs | 1 + src/librustc_middle/mir/mod.rs | 14 ++++++- src/librustc_middle/mir/tcx.rs | 7 ++++ src/librustc_middle/mir/type_foldable.rs | 2 + src/librustc_middle/mir/visit.rs | 2 + src/librustc_mir/borrow_check/invalidation.rs | 2 + src/librustc_mir/borrow_check/mod.rs | 2 + .../borrow_check/type_check/mod.rs | 2 + .../dataflow/impls/borrowed_locals.rs | 1 + .../dataflow/move_paths/builder.rs | 1 + src/librustc_mir/interpret/machine.rs | 7 ++++ src/librustc_mir/interpret/memory.rs | 2 + src/librustc_mir/interpret/step.rs | 6 +++ src/librustc_mir/interpret/validity.rs | 1 + src/librustc_mir/monomorphize/collector.rs | 1 + .../transform/check_consts/qualifs.rs | 4 +- .../transform/check_consts/validation.rs | 12 +++--- src/librustc_mir/transform/promote_consts.rs | 2 + .../transform/qualify_min_const_fn.rs | 3 ++ src/librustc_mir_build/build/expr/as_place.rs | 1 + .../build/expr/as_rvalue.rs | 1 + src/librustc_mir_build/build/expr/as_temp.rs | 16 ++++++-- src/librustc_mir_build/build/expr/category.rs | 1 + src/librustc_mir_build/build/expr/into.rs | 1 + src/librustc_mir_build/hair/cx/expr.rs | 21 +++++----- src/librustc_mir_build/hair/mod.rs | 2 + src/test/mir-opt/tls-access.rs | 13 ++++++ .../rustc.main.SimplifyCfg-final.after.mir | 40 +++++++++++++++++++ 31 files changed, 157 insertions(+), 23 deletions(-) create mode 100644 src/test/mir-opt/tls-access.rs create mode 100644 src/test/mir-opt/tls-access/rustc.main.SimplifyCfg-final.after.mir diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index 856f989bc10a1..a5cda5949eec3 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -259,6 +259,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance), GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); + assert!(!self.tcx.is_thread_local_static(def_id)); self.get_static(def_id) } }; diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index bb532abd84bde..57f72b1065d05 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -522,6 +522,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout }; (bx, operand) } + mir::Rvalue::ThreadLocalRef(def_id) => { + assert!(bx.cx().tcx().is_static(def_id)); + let static_ = bx.get_static(def_id); + let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id)); + let operand = OperandRef::from_immediate_or_packed_pair(&mut bx, static_, layout); + (bx, operand) + } mir::Rvalue::Use(ref operand) => { let operand = self.codegen_operand(&mut bx, operand); (bx, operand) @@ -745,6 +752,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::UnaryOp(..) | mir::Rvalue::Discriminant(..) | mir::Rvalue::NullaryOp(..) | + mir::Rvalue::ThreadLocalRef(_) | mir::Rvalue::Use(..) => // (*) true, mir::Rvalue::Repeat(..) | diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs index d32a147344992..3cc25a50a8781 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/src/librustc_middle/mir/interpret/error.rs @@ -513,6 +513,8 @@ pub enum UnsupportedOpInfo { // /// Encountered raw bytes where we needed a pointer. ReadBytesAsPointer, + /// Accessing thread local statics + ThreadLocalStatic(DefId), } impl fmt::Display for UnsupportedOpInfo { @@ -526,6 +528,7 @@ impl fmt::Display for UnsupportedOpInfo { NoMirFor(did) => write!(f, "no MIR body is available for {:?}", did), ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes",), ReadBytesAsPointer => write!(f, "unable to turn bytes into a pointer"), + ThreadLocalStatic(did) => write!(f, "accessing thread local static {:?}", did), } } } diff --git a/src/librustc_middle/mir/interpret/mod.rs b/src/librustc_middle/mir/interpret/mod.rs index 061bc9750e1c2..5e57b60894a58 100644 --- a/src/librustc_middle/mir/interpret/mod.rs +++ b/src/librustc_middle/mir/interpret/mod.rs @@ -209,6 +209,7 @@ pub fn specialized_encode_alloc_id<'tcx, E: Encoder>( fn_instance.encode(encoder)?; } GlobalAlloc::Static(did) => { + assert!(!tcx.is_thread_local_static(did)); // References to statics doesn't need to know about their allocations, // just about its `DefId`. AllocDiscriminant::Static.encode(encoder)?; diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 20c64d40fabbd..231f4d5e66927 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -2209,6 +2209,11 @@ pub enum Rvalue<'tcx> { /// &x or &mut x Ref(Region<'tcx>, BorrowKind, Place<'tcx>), + /// Accessing a thread local static. This is inherently a runtime operation, even if llvm + /// treats it as an access to a static. This `Rvalue` yields a reference to the thread local + /// static. + ThreadLocalRef(DefId), + /// Create a raw pointer to the given place /// Can be generated by raw address of expressions (`&raw const x`), /// or when casting a reference to a raw pointer. @@ -2348,6 +2353,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), + ThreadLocalRef(did) => ty::tls::with(|tcx| { + let muta = tcx.static_mutability(did).unwrap().prefix_str(); + write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) + }), Ref(region, borrow_kind, ref place) => { let kind_str = match borrow_kind { BorrowKind::Shared => "", @@ -2501,7 +2510,10 @@ impl Constant<'tcx> { pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option { match self.literal.val.try_to_scalar() { Some(Scalar::Ptr(ptr)) => match tcx.global_alloc(ptr.alloc_id) { - GlobalAlloc::Static(def_id) => Some(def_id), + GlobalAlloc::Static(def_id) => { + assert!(!tcx.is_thread_local_static(def_id)); + Some(def_id) + } _ => None, }, _ => None, diff --git a/src/librustc_middle/mir/tcx.rs b/src/librustc_middle/mir/tcx.rs index 4747aec2d5c24..e1325aadd40b6 100644 --- a/src/librustc_middle/mir/tcx.rs +++ b/src/librustc_middle/mir/tcx.rs @@ -152,6 +152,13 @@ impl<'tcx> Rvalue<'tcx> { Rvalue::Repeat(ref operand, count) => { tcx.mk_ty(ty::Array(operand.ty(local_decls, tcx), count)) } + Rvalue::ThreadLocalRef(did) => { + if tcx.is_mutable_static(did) { + tcx.mk_mut_ptr(tcx.type_of(did)) + } else { + tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.type_of(did)) + } + } Rvalue::Ref(reg, bk, ref place) => { let place_ty = place.ty(local_decls, tcx).ty; tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() }) diff --git a/src/librustc_middle/mir/type_foldable.rs b/src/librustc_middle/mir/type_foldable.rs index bb7001c1207bf..3512feb128ce3 100644 --- a/src/librustc_middle/mir/type_foldable.rs +++ b/src/librustc_middle/mir/type_foldable.rs @@ -173,6 +173,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { match *self { Use(ref op) => Use(op.fold_with(folder)), Repeat(ref op, len) => Repeat(op.fold_with(folder), len), + ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)), Ref(region, bk, ref place) => { Ref(region.fold_with(folder), bk, place.fold_with(folder)) } @@ -216,6 +217,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { match *self { Use(ref op) => op.visit_with(visitor), Repeat(ref op, _) => op.visit_with(visitor), + ThreadLocalRef(did) => did.visit_with(visitor), Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), AddressOf(_, ref place) => place.visit_with(visitor), Len(ref place) => place.visit_with(visitor), diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs index a29b7b75294b7..fa648a8807ebc 100644 --- a/src/librustc_middle/mir/visit.rs +++ b/src/librustc_middle/mir/visit.rs @@ -600,6 +600,8 @@ macro_rules! make_mir_visitor { self.visit_operand(value, location); } + Rvalue::ThreadLocalRef(_) => {} + Rvalue::Ref(r, bk, path) => { self.visit_region(r, location); let ctx = match bk { diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs index 178e3db17cd32..213dae130a9ed 100644 --- a/src/librustc_mir/borrow_check/invalidation.rs +++ b/src/librustc_mir/borrow_check/invalidation.rs @@ -295,6 +295,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { self.access_place(location, place, access_kind, LocalMutationIsAllowed::No); } + Rvalue::ThreadLocalRef(_) => {} + Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index e3098fc1cfc54..8238f40bbc862 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1290,6 +1290,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } + Rvalue::ThreadLocalRef(_) => {} + Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index ac7da7ee42d66..fdc3b291ba44a 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -2353,6 +2353,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } Rvalue::AddressOf(..) + | Rvalue::ThreadLocalRef(..) | Rvalue::Use(..) | Rvalue::Len(..) | Rvalue::BinaryOp(..) @@ -2368,6 +2369,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option { match rvalue { Rvalue::Use(_) + | Rvalue::ThreadLocalRef(_) | Rvalue::Repeat(..) | Rvalue::Ref(..) | Rvalue::AddressOf(..) diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index b61dc56407eb9..9905265741534 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -176,6 +176,7 @@ where mir::Rvalue::Cast(..) | mir::Rvalue::Use(..) + | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) | mir::Rvalue::Len(..) | mir::Rvalue::BinaryOp(..) diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 427ab1ca5cd22..2779c9e1073f3 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -324,6 +324,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { match *rvalue { + Rvalue::ThreadLocalRef(_) => {} // not-a-move Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::Cast(_, ref operand, _) diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 39b0218c5d73f..b5dc40d955191 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -358,6 +358,13 @@ pub trait Machine<'mir, 'tcx>: Sized { _mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer, ) -> InterpResult<'tcx, u64>; + + fn thread_local_alloc_id( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + did: DefId, + ) -> InterpResult<'tcx, AllocId> { + throw_unsup!(ThreadLocalStatic(did)) + } } // A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 61c365644c7f2..d7f64542aa78d 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -437,6 +437,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), None => throw_ub!(PointerUseAfterFree(id)), Some(GlobalAlloc::Static(def_id)) => { + assert!(!tcx.is_thread_local_static(def_id)); // Notice that every static has two `AllocId` that will resolve to the same // thing here: one maps to `GlobalAlloc::Static`, this is the "lazy" ID, // and the other one is maps to `GlobalAlloc::Memory`, this is returned by @@ -592,6 +593,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // be held throughout the match. match self.tcx.get_global_alloc(id) { Some(GlobalAlloc::Static(did)) => { + assert!(!self.tcx.is_thread_local_static(did)); // Use size and align of the type. let ty = self.tcx.type_of(did); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index fd9815975c19f..c15714260dc52 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -141,6 +141,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { use rustc_middle::mir::Rvalue::*; match *rvalue { + ThreadLocalRef(did) => { + let id = M::thread_local_alloc_id(self, did)?; + let val = Scalar::Ptr(self.tag_global_base_pointer(id.into())); + self.write_scalar(val, dest)?; + } + Use(ref operand) => { // Avoid recomputing the layout let op = self.eval_operand(operand, Some(dest.layout))?; diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index e962dfb2b3e86..b6676e8263e05 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -418,6 +418,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // Skip validation entirely for some external statics let alloc_kind = self.ecx.tcx.get_global_alloc(ptr.alloc_id); if let Some(GlobalAlloc::Static(did)) = alloc_kind { + assert!(!self.ecx.tcx.is_thread_local_static(did)); // See const_eval::machine::MemoryExtra::can_access_statics for why // this check is so important. // This check is reachable when the const just referenced the static, diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index c75e8414e8cca..6d7b0c830da4f 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1136,6 +1136,7 @@ fn create_mono_items_for_default_impls<'tcx>( fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec>) { match tcx.global_alloc(alloc_id) { GlobalAlloc::Static(def_id) => { + assert!(!tcx.is_thread_local_static(def_id)); let instance = Instance::mono(tcx, def_id); if should_monomorphize_locally(tcx, &instance) { trace!("collecting static {:?}", def_id); diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 05a7c78d59d39..5d604d8e3d716 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -153,7 +153,9 @@ where F: FnMut(Local) -> bool, { match rvalue { - Rvalue::NullaryOp(..) => Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)), + Rvalue::ThreadLocalRef(_) | Rvalue::NullaryOp(..) => { + Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) + } Rvalue::Discriminant(place) | Rvalue::Len(place) => { in_place::(cx, in_local, place.as_ref()) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 80094e154bf66..354fd200fc594 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -263,11 +263,11 @@ impl Validator<'mir, 'tcx> { } fn check_static(&mut self, def_id: DefId, span: Span) { - if self.tcx.is_thread_local_static(def_id) { - self.check_op_spanned(ops::ThreadLocalAccess, span) - } else { - self.check_op_spanned(ops::StaticAccess, span) - } + assert!( + !self.tcx.is_thread_local_static(def_id), + "tls access is checked in `Rvalue::ThreadLocalRef" + ); + self.check_op_spanned(ops::StaticAccess, span) } } @@ -332,6 +332,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { self.super_rvalue(rvalue, location); match *rvalue { + Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess), + Rvalue::Use(_) | Rvalue::Repeat(..) | Rvalue::UnaryOp(UnOp::Neg, _) diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 6caa2b48f3d45..2c8ad00fd06dc 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -603,6 +603,8 @@ impl<'tcx> Validator<'_, 'tcx> { } match rvalue { + Rvalue::ThreadLocalRef(_) => Err(Unpromotable), + Rvalue::NullaryOp(..) => Ok(()), Rvalue::Discriminant(place) | Rvalue::Len(place) => self.validate_place(place.as_ref()), diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index ead530bded861..5615aa84eecd7 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -156,6 +156,9 @@ fn check_rvalue( span: Span, ) -> McfResult { match rvalue { + Rvalue::ThreadLocalRef(_) => { + Err((span, "cannot access thread local storage in const fn".into())) + } Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { check_operand(tcx, operand, span, def_id, body) } diff --git a/src/librustc_mir_build/build/expr/as_place.rs b/src/librustc_mir_build/build/expr/as_place.rs index 16bba6ad14780..e811d68d5a5f8 100644 --- a/src/librustc_mir_build/build/expr/as_place.rs +++ b/src/librustc_mir_build/build/expr/as_place.rs @@ -258,6 +258,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } | ExprKind::Yield { .. } + | ExprKind::ThreadLocalRef(_) | ExprKind::Call { .. } => { // these are not places, so we need to make a temporary. debug_assert!(match Category::of(&expr.kind) { diff --git a/src/librustc_mir_build/build/expr/as_rvalue.rs b/src/librustc_mir_build/build/expr/as_rvalue.rs index 0f15190975087..9531ff0a9071f 100644 --- a/src/librustc_mir_build/build/expr/as_rvalue.rs +++ b/src/librustc_mir_build/build/expr/as_rvalue.rs @@ -53,6 +53,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = this.source_info(expr_span); match expr.kind { + ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)), ExprKind::Scope { region_scope, lint_level, value } => { let region_scope = (region_scope, source_info); this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value)) diff --git a/src/librustc_mir_build/build/expr/as_temp.rs b/src/librustc_mir_build/build/expr/as_temp.rs index d82abd8776719..901dadd661278 100644 --- a/src/librustc_mir_build/build/expr/as_temp.rs +++ b/src/librustc_mir_build/build/expr/as_temp.rs @@ -63,10 +63,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(tail_info) = this.block_context.currently_in_block_tail() { local_decl = local_decl.block_tail(tail_info); } - if let ExprKind::StaticRef { def_id, .. } = expr.kind { - let is_thread_local = this.hir.tcx().is_thread_local_static(def_id); - local_decl.internal = true; - local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local }); + match expr.kind { + ExprKind::StaticRef { def_id, .. } => { + assert!(!this.hir.tcx().is_thread_local_static(def_id)); + local_decl.internal = true; + local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local: false }); + } + ExprKind::ThreadLocalRef(def_id) => { + assert!(this.hir.tcx().is_thread_local_static(def_id)); + local_decl.internal = true; + local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local: true }); + } + _ => {} } this.local_decls.push(local_decl) }; diff --git a/src/librustc_mir_build/build/expr/category.rs b/src/librustc_mir_build/build/expr/category.rs index 59d3003c9f49a..fb4b7997b6a5a 100644 --- a/src/librustc_mir_build/build/expr/category.rs +++ b/src/librustc_mir_build/build/expr/category.rs @@ -65,6 +65,7 @@ impl Category { | ExprKind::Repeat { .. } | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } + | ExprKind::ThreadLocalRef(_) | ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => Some(Category::Constant), diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs index ff3c7ee3ee823..ac7477c19e339 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/src/librustc_mir_build/build/expr/into.rs @@ -444,6 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Tuple { .. } | ExprKind::Closure { .. } | ExprKind::Literal { .. } + | ExprKind::ThreadLocalRef(_) | ExprKind::StaticRef { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { // should be handled above diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index fd3c48b38badb..e58b5def1c243 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -855,20 +855,17 @@ fn convert_path_expr<'a, 'tcx>( // a constant reference (or constant raw pointer for `static mut`) in MIR Res::Def(DefKind::Static, id) => { let ty = cx.tcx.static_ptr_ty(id); - let ptr = cx.tcx.create_static_alloc(id); let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - ExprKind::Deref { - arg: Expr { - ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::StaticRef { - literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty), - def_id: id, - }, + let kind = if cx.tcx.is_thread_local_static(id) { + ExprKind::ThreadLocalRef(id) + } else { + let ptr = cx.tcx.create_static_alloc(id); + ExprKind::StaticRef { + literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty), + def_id: id, } - .to_ref(), - } + }; + ExprKind::Deref { arg: Expr { ty, temp_lifetime, span: expr.span, kind }.to_ref() } } Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id), diff --git a/src/librustc_mir_build/hair/mod.rs b/src/librustc_mir_build/hair/mod.rs index aba7a7a1b420c..a8b0f3eab4b04 100644 --- a/src/librustc_mir_build/hair/mod.rs +++ b/src/librustc_mir_build/hair/mod.rs @@ -284,6 +284,8 @@ crate enum ExprKind<'tcx> { operands: Vec>, options: InlineAsmOptions, }, + /// An expression taking a reference to a thread local. + ThreadLocalRef(DefId), LlvmInlineAsm { asm: &'tcx hir::LlvmInlineAsmInner, outputs: Vec>, diff --git a/src/test/mir-opt/tls-access.rs b/src/test/mir-opt/tls-access.rs new file mode 100644 index 0000000000000..4f3f6b1b3ac02 --- /dev/null +++ b/src/test/mir-opt/tls-access.rs @@ -0,0 +1,13 @@ +#![feature(thread_local)] + +#[thread_local] +static mut FOO: u8 = 3; + +fn main() { + unsafe { + let a = &FOO; + FOO = 42; + } +} + +// EMIT_MIR rustc.main.SimplifyCfg-final.after.mir diff --git a/src/test/mir-opt/tls-access/rustc.main.SimplifyCfg-final.after.mir b/src/test/mir-opt/tls-access/rustc.main.SimplifyCfg-final.after.mir new file mode 100644 index 0000000000000..e4798c2e32407 --- /dev/null +++ b/src/test/mir-opt/tls-access/rustc.main.SimplifyCfg-final.after.mir @@ -0,0 +1,40 @@ +// MIR for `main` after SimplifyCfg-final + +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/tls-access.rs:6:11: 6:11 + let _2: *mut u8; // in scope 0 at $DIR/tls-access.rs:8:18: 8:21 + let mut _3: *mut u8; // in scope 0 at $DIR/tls-access.rs:9:9: 9:12 + scope 1 { + let _1: &u8; // in scope 1 at $DIR/tls-access.rs:8:13: 8:14 + scope 2 { + debug a => _1; // in scope 2 at $DIR/tls-access.rs:8:13: 8:14 + } + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/tls-access.rs:8:13: 8:14 + StorageLive(_2); // scope 1 at $DIR/tls-access.rs:8:18: 8:21 + _2 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls-access.rs:8:18: 8:21 + _1 = &(*_2); // scope 1 at $DIR/tls-access.rs:8:17: 8:21 + StorageLive(_3); // scope 2 at $DIR/tls-access.rs:9:9: 9:12 + _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls-access.rs:9:9: 9:12 + (*_3) = const 42u8; // scope 2 at $DIR/tls-access.rs:9:9: 9:17 + // ty::Const + // + ty: u8 + // + val: Value(Scalar(0x2a)) + // mir::Constant + // + span: $DIR/tls-access.rs:9:15: 9:17 + // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) } + StorageDead(_3); // scope 2 at $DIR/tls-access.rs:9:17: 9:18 + _0 = const (); // scope 1 at $DIR/tls-access.rs:7:5: 10:6 + // ty::Const + // + ty: () + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/tls-access.rs:7:5: 10:6 + // + literal: Const { ty: (), val: Value(Scalar()) } + StorageDead(_2); // scope 1 at $DIR/tls-access.rs:10:5: 10:6 + StorageDead(_1); // scope 1 at $DIR/tls-access.rs:10:5: 10:6 + return; // scope 0 at $DIR/tls-access.rs:11:2: 11:2 + } +} From 4b7e44f89317ecd8162db8ab0286003205c3f886 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 30 May 2020 12:30:58 +0100 Subject: [PATCH 460/695] rustdoc: remove calls to `local_def_id_from_node_id` --- src/librustdoc/clean/inline.rs | 8 ++------ src/librustdoc/clean/mod.rs | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4bf3649dcc2e2..08e04f719e9ba 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -6,7 +6,7 @@ use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::Mutability; use rustc_metadata::creader::LoadedMacro; use rustc_middle::ty; @@ -454,11 +454,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet) name: None, attrs: clean::Attributes::default(), source: clean::Span::empty(), - def_id: cx - .tcx - .hir() - .local_def_id_from_node_id(ast::CRATE_NODE_ID) - .to_def_id(), + def_id: DefId::local(CRATE_DEF_INDEX), visibility: clean::Public, stability: None, deprecation: None, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 702c7d1e0f120..371df7444b004 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1549,11 +1549,11 @@ impl<'tcx> Clean for Ty<'tcx> { ty::FnDef(..) | ty::FnPtr(_) => { let ty = cx.tcx.lift(self).expect("FnPtr lift failed"); let sig = ty.fn_sig(cx.tcx); - let local_def_id = cx.tcx.hir().local_def_id_from_node_id(ast::CRATE_NODE_ID); + let def_id = DefId::local(CRATE_DEF_INDEX); BareFunction(box BareFunctionDecl { unsafety: sig.unsafety(), generic_params: Vec::new(), - decl: (local_def_id.to_def_id(), sig).clean(cx), + decl: (def_id, sig).clean(cx), abi: sig.abi(), }) } @@ -2255,7 +2255,7 @@ impl Clean> for doctree::Import<'_> { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.tcx.hir().local_def_id_from_node_id(ast::CRATE_NODE_ID).to_def_id(), + def_id: DefId::local(CRATE_DEF_INDEX), visibility: self.vis.clean(cx), stability: None, deprecation: None, From a8e4236edc1e118ccb6c3f3a8d0139e4cd90b5b8 Mon Sep 17 00:00:00 2001 From: Felix S Klock II Date: Sat, 30 May 2020 08:19:35 -0400 Subject: [PATCH 461/695] add fixme suggested by eddyb --- src/librustc_span/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index e17fe1fa782cb..94795e635586c 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -81,7 +81,10 @@ impl Globals { scoped_tls::scoped_thread_local!(pub static GLOBALS: Globals); -/// FIXME: Perhaps this should not implement Rustc{Decodable, Encodable} +// FIXME: Perhaps this should not implement Rustc{Decodable, Encodable} +// +// FIXME: We should use this enum or something like it to get rid of the +// use of magic `/rust/1.x/...` paths across the board. #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, RustcDecodable, RustcEncodable)] #[derive(HashStable_Generic)] pub enum RealFileName { From 372ba2a03d7180c3a58631ecbd93e8912e697bab Mon Sep 17 00:00:00 2001 From: marmeladema Date: Sat, 30 May 2020 14:38:46 +0100 Subject: [PATCH 462/695] Use `LocalDefId` instead of `NodeId` in `resolve_str_path_error` --- src/librustc_resolve/lib.rs | 7 ++----- src/librustdoc/core.rs | 10 +++++++--- src/librustdoc/passes/collect_intra_doc_links.rs | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b50f9fe8e907d..e5fc23e14d2ab 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2902,7 +2902,7 @@ impl<'a> Resolver<'a> { span: Span, path_str: &str, ns: Namespace, - module_id: NodeId, + module_id: LocalDefId, ) -> Result<(ast::Path, Res), ()> { let path = if path_str.starts_with("::") { ast::Path { @@ -2922,10 +2922,7 @@ impl<'a> Resolver<'a> { .collect(), } }; - let module = self.block_map.get(&module_id).copied().unwrap_or_else(|| { - let def_id = self.definitions.local_def_id(module_id); - self.module_map.get(&def_id).copied().unwrap_or(self.graph_root) - }); + let module = self.module_map.get(&module_id).copied().unwrap_or(self.graph_root); let parent_scope = &ParentScope::module(module); let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?; Ok((path, res)) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 99ca7084c30dd..06293a987124e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,4 +1,3 @@ -use rustc_ast::ast::CRATE_NODE_ID; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; @@ -7,7 +6,7 @@ use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; use rustc_hir::def::Namespace::TypeNS; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::HirId; use rustc_interface::interface; use rustc_middle::middle::cstore::CrateStore; @@ -390,7 +389,12 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt resolver.borrow_mut().access(|resolver| { for extern_name in &extern_names { resolver - .resolve_str_path_error(DUMMY_SP, extern_name, TypeNS, CRATE_NODE_ID) + .resolve_str_path_error( + DUMMY_SP, + extern_name, + TypeNS, + LocalDefId { local_def_index: CRATE_DEF_INDEX }, + ) .unwrap_or_else(|()| { panic!("Unable to resolve external crate {}", extern_name) }); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index adb7fc3eb9cff..149480ec80f29 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{ Namespace::{self, *}, PerNS, Res, }; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty; use rustc_resolve::ParentScope; use rustc_session::lint; @@ -61,7 +61,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &self, path_str: &str, current_item: &Option, - module_id: rustc_ast::ast::NodeId, + module_id: LocalDefId, ) -> Result<(Res, Option), ErrorKind> { let cx = self.cx; @@ -137,7 +137,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // In case we're in a module, try to resolve the relative path. if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) { - let module_id = cx.tcx.hir().hir_id_to_node_id(module_id); + let module_id = cx.tcx.hir().local_def_id(module_id); let result = cx.enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) }); From 0fb6e63c0438ace4ad9d496376af955c0baacf04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 17:13:07 +0200 Subject: [PATCH 463/695] encode_utf8_raw is not always valid UTF-8; clarify comments --- src/libcore/char/methods.rs | 19 ++++++++++++------- src/libstd/sys_common/wtf8.rs | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index b1b3c70efb1c7..bf09b28ff693e 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -661,7 +661,8 @@ impl char { #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - encode_utf8_raw(self as u32, dst) + // SAFETY: `char` is not a surrogate, so this is valid UTF-8. + unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } } /// Encodes this character as UTF-16 into the provided `u16` buffer, @@ -1631,7 +1632,11 @@ fn len_utf8(code: u32) -> usize { /// Encodes a raw u32 value as UTF-8 into the provided byte buffer, /// and then returns the subslice of the buffer that contains the encoded character. /// -/// Unlike `char::encode_utf8`, this method can be called on codepoints in the surrogate range. +/// Unlike `char::encode_utf8`, this method also handles codepoints in the surrogate range. +/// (Creating a `char` in the surrogate range is UB.) +/// The result is valid [generalized UTF-8] but not valid UTF-8. +/// +/// [generalized UTF-8]: https://simonsapin.github.io/wtf-8/#generalized-utf8 /// /// # Panics /// @@ -1640,7 +1645,7 @@ fn len_utf8(code: u32) -> usize { #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] #[doc(hidden)] #[inline] -pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut str { +pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { let len = len_utf8(code); match (len, &mut dst[..]) { (1, [a, ..]) => { @@ -1668,14 +1673,14 @@ pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut str { dst.len(), ), }; - // SAFETY: We just wrote UTF-8 content in, so converting to str is fine. - unsafe { from_utf8_unchecked_mut(&mut dst[..len]) } + &mut dst[..len] } /// Encodes a raw u32 value as UTF-16 into the provided `u16` buffer, /// and then returns the subslice of the buffer that contains the encoded character. /// -/// Unlike `char::encode_utf16`, this method can be called on codepoints in the surrogate range. +/// Unlike `char::encode_utf16`, this method also handles codepoints in the surrogate range. +/// (Creating a `char` in the surrogate range is UB.) /// /// # Panics /// @@ -1688,7 +1693,7 @@ pub fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] { // SAFETY: each arm checks whether there are enough bits to write into unsafe { if (code & 0xFFFF) == code && !dst.is_empty() { - // The BMP falls through (assuming non-surrogate, as it should) + // The BMP falls through *dst.get_unchecked_mut(0) = code as u16; slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) } else if dst.len() >= 2 { diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 9f589c93ae59c..ccb54b7e68d18 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -202,7 +202,7 @@ impl Wtf8Buf { /// This does **not** include the WTF-8 concatenation check. fn push_code_point_unchecked(&mut self, code_point: CodePoint) { let mut bytes = [0; 4]; - let bytes = char::encode_utf8_raw(code_point.value, &mut bytes).as_bytes(); + let bytes = char::encode_utf8_raw(code_point.value, &mut bytes); self.bytes.extend_from_slice(bytes) } From 5faab874f9f8655c8f284944b5acdede5c088af4 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sat, 23 May 2020 00:07:09 +0200 Subject: [PATCH 464/695] new lint: vec_resize_to_zero --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 5 +++ clippy_lints/src/utils/paths.rs | 1 + clippy_lints/src/vec_resize_to_zero.rs | 59 ++++++++++++++++++++++++++ src/lintlist/mod.rs | 7 +++ tests/ui/vec_resize_to_zero.rs | 15 +++++++ tests/ui/vec_resize_to_zero.stderr | 13 ++++++ 7 files changed, 101 insertions(+) create mode 100644 clippy_lints/src/vec_resize_to_zero.rs create mode 100644 tests/ui/vec_resize_to_zero.rs create mode 100644 tests/ui/vec_resize_to_zero.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ac9057199ff3..f7dae3dcfff0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1630,6 +1630,7 @@ Released 2018-09-13 [`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute [`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec [`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box +[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 902f3d56c1e4f..4f0ecab393d03 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -325,6 +325,7 @@ mod unwrap; mod use_self; mod useless_conversion; mod vec; +mod vec_resize_to_zero; mod verbose_file_reads; mod wildcard_dependencies; mod wildcard_imports; @@ -847,6 +848,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &utils::internal_lints::OUTER_EXPN_EXPN_DATA, &utils::internal_lints::PRODUCE_ICE, &vec::USELESS_VEC, + &vec_resize_to_zero::VEC_RESIZE_TO_ZERO, &verbose_file_reads::VERBOSE_FILE_READS, &wildcard_dependencies::WILDCARD_DEPENDENCIES, &wildcard_imports::ENUM_GLOB_USE, @@ -1062,6 +1064,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive); store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); + store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { single_char_binding_names_threshold, @@ -1430,6 +1433,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&vec::USELESS_VEC), + LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), LintId::of(&write::PRINTLN_EMPTY_STRING), LintId::of(&write::PRINT_LITERAL), LintId::of(&write::PRINT_WITH_NEWLINE), @@ -1677,6 +1681,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), + LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), ]); store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 779da7e6bf23c..3b7e9739211b0 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -138,5 +138,6 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"]; pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"]; pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; +pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs new file mode 100644 index 0000000000000..86cbfa8203d54 --- /dev/null +++ b/clippy_lints/src/vec_resize_to_zero.rs @@ -0,0 +1,59 @@ +use crate::utils::span_lint_and_then; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; + +use crate::utils::{match_def_path, paths}; +use rustc_ast::ast::LitKind; +use rustc_hir as hir; + +declare_clippy_lint! { + /// **What it does:** Finds occurences of `Vec::resize(0, an_int)` + /// + /// **Why is this bad?** This is probably an argument inversion mistake. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// vec!(1, 2, 3, 4, 5).resize(0, 5) + /// ``` + pub VEC_RESIZE_TO_ZERO, + correctness, + "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" +} + +declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VecResizeToZero { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + if let hir::ExprKind::MethodCall(path_segment, _, ref args) = expr.kind; + if let Some(method_def_id) = cx.tables.type_dependent_def_id(expr.hir_id); + if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3; + if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind; + if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind; + then { + let method_call_span = expr.span.with_lo(path_segment.ident.span.lo()); + span_lint_and_then( + cx, + VEC_RESIZE_TO_ZERO, + expr.span, + "emptying a vector with `resize`", + |db| { + db.help("the arguments may be inverted..."); + db.span_suggestion( + method_call_span, + "...or you can empty the vector with", + "clear()".to_string(), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f63301c7db0a6..1e94ca00c1457 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2460,6 +2460,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "types", }, + Lint { + name: "vec_resize_to_zero", + group: "correctness", + desc: "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake", + deprecation: None, + module: "vec_resize_to_zero", + }, Lint { name: "verbose_bit_mask", group: "style", diff --git a/tests/ui/vec_resize_to_zero.rs b/tests/ui/vec_resize_to_zero.rs new file mode 100644 index 0000000000000..0263e2f5f20c1 --- /dev/null +++ b/tests/ui/vec_resize_to_zero.rs @@ -0,0 +1,15 @@ +#![warn(clippy::vec_resize_to_zero)] + +fn main() { + // applicable here + vec![1, 2, 3, 4, 5].resize(0, 5); + + // not applicable + vec![1, 2, 3, 4, 5].resize(2, 5); + + // applicable here, but only implemented for integer litterals for now + vec!["foo", "bar", "baz"].resize(0, "bar"); + + // not applicable + vec!["foo", "bar", "baz"].resize(2, "bar") +} diff --git a/tests/ui/vec_resize_to_zero.stderr b/tests/ui/vec_resize_to_zero.stderr new file mode 100644 index 0000000000000..feb846298c656 --- /dev/null +++ b/tests/ui/vec_resize_to_zero.stderr @@ -0,0 +1,13 @@ +error: emptying a vector with `resize` + --> $DIR/vec_resize_to_zero.rs:5:5 + | +LL | vec![1, 2, 3, 4, 5].resize(0, 5); + | ^^^^^^^^^^^^^^^^^^^^------------ + | | + | help: ...or you can empty the vector with: `clear()` + | + = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings` + = help: the arguments may be inverted... + +error: aborting due to previous error + From 5a813b6dd66d8056c62d268479c0b27dcd697554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Woimb=C3=A9e?= Date: Wed, 27 May 2020 18:31:22 +0200 Subject: [PATCH 465/695] Fix missing parentheses Fn notation error --- src/librustc_typeck/astconv.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 12edfed19c07e..ab9db159038af 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1151,9 +1151,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .as_ref() .and_then(|args| args.args.get(0)) .and_then(|arg| match arg { - hir::GenericArg::Type(ty) => { - sess.source_map().span_to_snippet(ty.span).ok() + hir::GenericArg::Type(ty) => match ty.kind { + hir::TyKind::Tup(t) => t + .iter() + .map(|e| sess.source_map().span_to_snippet(e.span)) + .collect::, _>>() + .map(|a| a.join(", ")), + _ => sess.source_map().span_to_snippet(ty.span), } + .map(|s| format!("({})", s)) + .ok(), _ => None, }) .unwrap_or_else(|| "()".to_string()), From c54d4fe93f1640fee0be7bfe9c525938dde558e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arthur=20Woimb=C3=A9e?= Date: Sat, 30 May 2020 18:29:45 +0200 Subject: [PATCH 466/695] Test ui suggestion fn trait notation --- .../ui/suggestions/fn-trait-notation.fixed | 19 ++++++++++++ src/test/ui/suggestions/fn-trait-notation.rs | 19 ++++++++++++ .../ui/suggestions/fn-trait-notation.stderr | 30 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 src/test/ui/suggestions/fn-trait-notation.fixed create mode 100644 src/test/ui/suggestions/fn-trait-notation.rs create mode 100644 src/test/ui/suggestions/fn-trait-notation.stderr diff --git a/src/test/ui/suggestions/fn-trait-notation.fixed b/src/test/ui/suggestions/fn-trait-notation.fixed new file mode 100644 index 0000000000000..cf940f4e9267a --- /dev/null +++ b/src/test/ui/suggestions/fn-trait-notation.fixed @@ -0,0 +1,19 @@ +// run-rustfix +fn e0658(f: F, g: G, h: H) -> i32 +where + F: Fn(i32) -> i32, //~ ERROR E0658 + G: Fn(i32, i32) -> (i32, i32), //~ ERROR E0658 + H: Fn(i32) -> i32, //~ ERROR E0658 +{ + f(3); + g(3, 4); + h(3) +} + +fn main() { + e0658( + |a| a, + |a, b| (b, a), + |a| a, + ); +} diff --git a/src/test/ui/suggestions/fn-trait-notation.rs b/src/test/ui/suggestions/fn-trait-notation.rs new file mode 100644 index 0000000000000..f0bb03315d987 --- /dev/null +++ b/src/test/ui/suggestions/fn-trait-notation.rs @@ -0,0 +1,19 @@ +// run-rustfix +fn e0658(f: F, g: G, h: H) -> i32 +where + F: Fn, //~ ERROR E0658 + G: Fn<(i32, i32, ), Output = (i32, i32)>, //~ ERROR E0658 + H: Fn<(i32,), Output = i32>, //~ ERROR E0658 +{ + f(3); + g(3, 4); + h(3) +} + +fn main() { + e0658( + |a| a, + |a, b| (b, a), + |a| a, + ); +} diff --git a/src/test/ui/suggestions/fn-trait-notation.stderr b/src/test/ui/suggestions/fn-trait-notation.stderr new file mode 100644 index 0000000000000..3e3b541744017 --- /dev/null +++ b/src/test/ui/suggestions/fn-trait-notation.stderr @@ -0,0 +1,30 @@ +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change + --> $DIR/fn-trait-notation.rs:4:8 + | +LL | F: Fn, + | ^^^^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(i32) -> i32` + | + = note: see issue #29625 for more information + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change + --> $DIR/fn-trait-notation.rs:5:8 + | +LL | G: Fn<(i32, i32, ), Output = (i32, i32)>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(i32, i32) -> (i32, i32)` + | + = note: see issue #29625 for more information + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change + --> $DIR/fn-trait-notation.rs:6:8 + | +LL | H: Fn<(i32,), Output = i32>, + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(i32) -> i32` + | + = note: see issue #29625 for more information + = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. From b0e524d444ea1a060b248b7ffedd48693f14285b Mon Sep 17 00:00:00 2001 From: Poliorcetics Date: Sat, 30 May 2020 18:58:54 +0200 Subject: [PATCH 467/695] Apply suggestions from code review Fix suggestions from review. Co-authored-by: Bastian Kauschke --- src/libstd/keyword_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index f74ee6a3e9b00..a957bcf215f27 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1220,7 +1220,7 @@ mod unsafe_keyword {} /// though a number of convenient shortcuts are supported: /// /// * Simultaneously binding a list of paths with a common prefix, -/// using the glob-like brace syntax use `a::b::{c, d, e::f, g::h::i};` +/// using the glob-like brace syntax `use a::b::{c, d, e::f, g::h::i};` /// * Simultaneously binding a list of paths with a common prefix and their common parent module, /// using the [`self`] keyword, such as `use a::b::{self, c, d::e};` /// * Rebinding the target name as a new local name, using the syntax `use p::q::r as x;`. @@ -1230,7 +1230,7 @@ mod unsafe_keyword {} /// * Nesting groups of the previous features multiple times, /// such as `use a::b::{self as ab, c, d::{*, e::f}};` /// * Reexporting with visibility modifiers such as `pub use a::b;` -/// * Importing with `_` to only import the methods of the item without binding it to a name +/// * Importing with `_` to only import the methods of a trait without binding it to a name /// (to avoid conflict for example): `use ::std::io::Read as _;`. /// /// Using path qualifiers like [`crate`], [`super`] or [`self`] is supported: `use crate::a::b;`. From 4bae9e59373e2ef405ea2601822137bd72122ef6 Mon Sep 17 00:00:00 2001 From: Poliorcetics Date: Sat, 30 May 2020 19:18:05 +0200 Subject: [PATCH 468/695] Remove the fn main() in code example --- src/libstd/keyword_docs.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a957bcf215f27..a4996d9eee810 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1238,8 +1238,7 @@ mod unsafe_keyword {} /// Note that when the wildcard `*` is used on a type, it does not import its methods (though /// for `enum`s it imports the variants, as shown in the example below). /// -/// ```compile_fail -/// # fn main() { +/// ```compile_fail,edition2018 /// enum ExampleEnum { /// VariantA, /// VariantB, @@ -1258,7 +1257,6 @@ mod unsafe_keyword {} /// /// // Does not compile ! /// let n = new(); -/// # } /// ``` /// /// For more information on `use` and paths in general, see the [Reference]. From f49ebbb891c2b6d3226bf77fd82c9cd22e389f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 24 May 2020 10:34:03 -0700 Subject: [PATCH 469/695] Account for missing lifetime in opaque return type When encountering an opaque closure return type that needs to bound a lifetime to the function's arguments, including borrows and type params, provide appropriate suggestions that lead to working code. Get the user from ```rust fn foo(g: G, dest: &mut T) -> impl FnOnce() where G: Get { move || { *dest = g.get(); } } ``` to ```rust fn foo<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() +'a where G: Get { move || { *dest = g.get(); } } ``` --- .../infer/error_reporting/mod.rs | 140 ++++++++++++----- .../nice_region_error/static_impl_trait.rs | 17 +- .../infer/error_reporting/note.rs | 25 ++- .../missing-lifetimes-in-signature.rs | 100 ++++++++++++ .../missing-lifetimes-in-signature.stderr | 146 ++++++++++++++++++ 5 files changed, 359 insertions(+), 69 deletions(-) create mode 100644 src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs create mode 100644 src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index ae9019828170f..3b98d47778fc1 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -1682,49 +1682,70 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, ) -> DiagnosticBuilder<'a> { + let hir = &self.tcx.hir(); // Attempt to obtain the span of the parameter so we can // suggest adding an explicit lifetime bound to it. - let type_param_span = match (self.in_progress_tables, bound_kind) { - (Some(ref table), GenericKind::Param(ref param)) => { - let table_owner = table.borrow().hir_owner; - table_owner.and_then(|table_owner| { - let generics = self.tcx.generics_of(table_owner.to_def_id()); - // Account for the case where `param` corresponds to `Self`, - // which doesn't have the expected type argument. - if !(generics.has_self && param.index == 0) { - let type_param = generics.type_param(param, self.tcx); - let hir = &self.tcx.hir(); - type_param.def_id.as_local().map(|def_id| { - // Get the `hir::Param` to verify whether it already has any bounds. - // We do this to avoid suggesting code that ends up as `T: 'a'b`, - // instead we suggest `T: 'a + 'b` in that case. - let id = hir.as_local_hir_id(def_id); - let mut has_bounds = false; - if let Node::GenericParam(param) = hir.get(id) { - has_bounds = !param.bounds.is_empty(); - } - let sp = hir.span(id); - // `sp` only covers `T`, change it so that it covers - // `T:` when appropriate - let is_impl_trait = bound_kind.to_string().starts_with("impl "); - let sp = if has_bounds && !is_impl_trait { - sp.to(self - .tcx - .sess - .source_map() - .next_point(self.tcx.sess.source_map().next_point(sp))) - } else { - sp - }; - (sp, has_bounds, is_impl_trait) - }) - } else { - None - } - }) + let generics = self + .in_progress_tables + .and_then(|table| table.borrow().hir_owner) + .map(|table_owner| self.tcx.generics_of(table_owner.to_def_id())); + let type_param_span = match (generics, bound_kind) { + (Some(ref generics), GenericKind::Param(ref param)) => { + // Account for the case where `param` corresponds to `Self`, + // which doesn't have the expected type argument. + if !(generics.has_self && param.index == 0) { + let type_param = generics.type_param(param, self.tcx); + type_param.def_id.as_local().map(|def_id| { + // Get the `hir::Param` to verify whether it already has any bounds. + // We do this to avoid suggesting code that ends up as `T: 'a'b`, + // instead we suggest `T: 'a + 'b` in that case. + let id = hir.as_local_hir_id(def_id); + let mut has_bounds = false; + if let Node::GenericParam(param) = hir.get(id) { + has_bounds = !param.bounds.is_empty(); + } + let sp = hir.span(id); + // `sp` only covers `T`, change it so that it covers + // `T:` when appropriate + let is_impl_trait = bound_kind.to_string().starts_with("impl "); + let sp = if has_bounds && !is_impl_trait { + sp.to(self + .tcx + .sess + .source_map() + .next_point(self.tcx.sess.source_map().next_point(sp))) + } else { + sp + }; + (sp, has_bounds, is_impl_trait) + }) + } else { + None + } } _ => None, }; + let new_lt = generics + .as_ref() + .and_then(|g| { + let possible = ["'a", "'b", "'c", "'d", "'e", "'f", "'g", "'h", "'i", "'j", "'k"]; + let lts_names = g + .params + .iter() + .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) + .map(|p| p.name.as_str()) + .collect::>(); + let lts = lts_names.iter().map(|s| -> &str { &*s }).collect::>(); + possible.iter().filter(|&candidate| !lts.contains(&*candidate)).next().map(|s| *s) + }) + .unwrap_or("'lt"); + let add_lt_sugg = generics + .as_ref() + .and_then(|g| g.params.first()) + .and_then(|param| param.def_id.as_local()) + .map(|def_id| { + (hir.span(hir.as_local_hir_id(def_id)).shrink_to_lo(), format!("{}, ", new_lt)) + }); let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), @@ -1781,6 +1802,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + let new_binding_suggestion = + |err: &mut DiagnosticBuilder<'tcx>, + type_param_span: Option<(Span, bool, bool)>, + bound_kind: GenericKind<'tcx>| { + let msg = "consider introducing an explicit lifetime bound to unify the type \ + parameter and the output"; + if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span { + let suggestion = if is_impl_trait { + (sp.shrink_to_hi(), format!(" + {}", new_lt)) + } else { + let tail = if has_lifetimes { " +" } else { "" }; + (sp, format!("{}: {}{}", bound_kind, new_lt, tail)) + }; + let mut sugg = + vec![suggestion, (span.shrink_to_hi(), format!(" + {}", new_lt))]; + if let Some(lt) = add_lt_sugg { + sugg.push(lt); + sugg.rotate_right(1); + } + // `MaybeIncorrect` due to issue #41966. + err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); + } + }; + let mut err = match *sub { ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. }) | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }) => { @@ -1822,10 +1867,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "{} may not live long enough", labeled_user_string ); - err.help(&format!( - "consider adding an explicit lifetime bound for `{}`", - bound_kind - )); note_and_explain_region( self.tcx, &mut err, @@ -1833,6 +1874,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sub, "...", ); + if let Some(infer::RelateParamBound(_, t)) = origin { + let t = self.resolve_vars_if_possible(&t); + match t.kind { + // We've got: + // fn get_later(g: G, dest: &mut T) -> impl FnOnce() + '_ + // suggest: + // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + ty::Closure(_, _substs) | ty::Opaque(_, _substs) => { + new_binding_suggestion(&mut err, type_param_span, bound_kind); + } + _ => { + binding_suggestion(&mut err, type_param_span, bound_kind, new_lt); + } + } + } err } }; diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 7f3ec852e41de..4ad587db0128d 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -4,7 +4,7 @@ use crate::infer::error_reporting::msg_span_from_free_region; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use rustc_errors::{Applicability, ErrorReported}; -use rustc_middle::ty::{BoundRegion, FreeRegion, RegionKind}; +use rustc_middle::ty::RegionKind; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static impl Trait. @@ -37,13 +37,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_note(lifetime_sp, &format!("...can't outlive {}", lifetime)); } - let lifetime_name = match sup_r { - RegionKind::ReFree(FreeRegion { - bound_region: BoundRegion::BrNamed(_, ref name), - .. - }) => name.to_string(), - _ => "'_".to_owned(), - }; + let lifetime_name = + if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; let fn_return_span = return_ty.unwrap().1; if let Ok(snippet) = self.tcx().sess.source_map().span_to_snippet(fn_return_span) @@ -54,9 +49,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_suggestion( fn_return_span, &format!( - "you can add a bound to the return type to make it last \ - less than `'static` and match {}", - lifetime, + "you can add a bound to the return type to make it last less \ + than `'static` and match {}", + lifetime ), format!("{} + {}", snippet, lifetime_name), Applicability::Unspecified, diff --git a/src/librustc_infer/infer/error_reporting/note.rs b/src/librustc_infer/infer/error_reporting/note.rs index 8fbb89da5af41..968c488bc004e 100644 --- a/src/librustc_infer/infer/error_reporting/note.rs +++ b/src/librustc_infer/infer/error_reporting/note.rs @@ -56,8 +56,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_note( span, &format!( - "...so that the reference type `{}` does not outlive the \ - data it points at", + "...so that the reference type `{}` does not outlive the data it points at", self.ty_to_string(ty) ), ); @@ -66,8 +65,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_note( span, &format!( - "...so that the type `{}` will meet its required \ - lifetime bounds", + "...so that the type `{}` will meet its required lifetime bounds", self.ty_to_string(t) ), ); @@ -81,8 +79,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::CompareImplMethodObligation { span, .. } => { err.span_note( span, - "...so that the definition in impl matches the definition from the \ - trait", + "...so that the definition in impl matches the definition from the trait", ); } } @@ -113,8 +110,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, span, E0312, - "lifetime of reference outlives lifetime of \ - borrowed content..." + "lifetime of reference outlives lifetime of borrowed content..." ); note_and_explain_region( self.tcx, @@ -138,8 +134,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, span, E0313, - "lifetime of borrowed pointer outlives lifetime \ - of captured variable `{}`...", + "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...", var_name ); note_and_explain_region( @@ -163,8 +158,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, span, E0476, - "lifetime of the source pointer does not outlive \ - lifetime bound of the object type" + "lifetime of the source pointer does not outlive lifetime bound of the \ + object type" ); note_and_explain_region(self.tcx, &mut err, "object type is valid for ", sub, ""); note_and_explain_region( @@ -181,8 +176,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, span, E0477, - "the type `{}` does not fulfill the required \ - lifetime", + "the type `{}` does not fulfill the required lifetime", self.ty_to_string(ty) ); match *sub { @@ -217,8 +211,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, span, E0482, - "lifetime of return value does not outlive the \ - function call" + "lifetime of return value does not outlive the function call" ); note_and_explain_region( self.tcx, diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs new file mode 100644 index 0000000000000..b5f6fdeaa4ed0 --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -0,0 +1,100 @@ +pub trait Get { + fn get(self) -> T; +} + +struct Foo { + x: usize, +} + +impl Get for Foo { + fn get(self) -> usize { + self.x + } +} + +fn foo(g: G, dest: &mut T) -> impl FnOnce() +where + G: Get +{ + move || { //~ ERROR cannot infer an appropriate lifetime + *dest = g.get(); + } +} + +// After applying suggestion for `foo`: +fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ +//~^ ERROR the parameter type `G` may not live long enough +where + G: Get +{ + move || { + *dest = g.get(); + } +} + + +// After applying suggestion for `bar`: +fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ //~ ERROR undeclared lifetime +where + G: Get +{ + move || { + *dest = g.get(); + } +} + +// After applying suggestion for `baz`: +fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ +//~^ ERROR the parameter type `G` may not live long enough +where + G: Get +{ + move || { + *dest = g.get(); + } +} + +// After applying suggestion for `qux`: +// FIXME: we should suggest be suggesting to change `dest` to `&'a mut T`. +fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a +where + G: Get +{ + move || { //~ ERROR cannot infer an appropriate lifetime + *dest = g.get(); + } +} + +// Potential incorrect attempt: +fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a +//~^ ERROR the parameter type `G` may not live long enough +where + G: Get +{ + move || { + *dest = g.get(); + } +} + + +// We need to tie the lifetime of `G` with the lifetime of `&mut T` and the returned closure: +fn ok<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a +where + G: Get +{ + move || { + *dest = g.get(); + } +} + +// This also works. The `'_` isn't necessary but it's where we arrive to following the suggestions: +fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a +where + G: Get +{ + move || { + *dest = g.get(); + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr new file mode 100644 index 0000000000000..d69db90f3bacc --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -0,0 +1,146 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/missing-lifetimes-in-signature.rs:37:11 + | +LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `'a,` + +error: cannot infer an appropriate lifetime + --> $DIR/missing-lifetimes-in-signature.rs:19:5 + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + | ------------- this return type evaluates to the `'static` lifetime... +... +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ ...but this borrow... + | +note: ...can't outlive the anonymous lifetime #1 defined on the function body at 15:1 + --> $DIR/missing-lifetimes-in-signature.rs:15:1 + | +LL | / fn foo(g: G, dest: &mut T) -> impl FnOnce() +LL | | where +LL | | G: Get +LL | | { +... | +LL | | } +LL | | } + | |_^ +help: you can add a bound to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 15:1 + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:25:37 + | +LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 25:1... + --> $DIR/missing-lifetimes-in-signature.rs:25:1 + | +LL | / fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ +LL | | +LL | | where +LL | | G: Get +... | +LL | | } +LL | | } + | |_^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6 g:G, dest:&mut T]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:25:37 + | +LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime bound to unify the type parameter and the output + | +LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ^^^^^ ^^^^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:47:45 + | +LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 47:1... + --> $DIR/missing-lifetimes-in-signature.rs:47:1 + | +LL | / fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ +LL | | +LL | | where +LL | | G: Get +... | +LL | | } +LL | | } + | |_^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6 g:G, dest:&mut T]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:47:45 + | +LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime bound to unify the type parameter and the output + | +LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b + | ^^^ ^^^^^^^ ^^^^ + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/missing-lifetimes-in-signature.rs:63:5 + | +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 59:1... + --> $DIR/missing-lifetimes-in-signature.rs:59:1 + | +LL | / fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a +LL | | where +LL | | G: Get +LL | | { +... | +LL | | } +LL | | } + | |_^ +note: ...so that the types are compatible + --> $DIR/missing-lifetimes-in-signature.rs:63:5 + | +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ + = note: expected `&mut T` + found `&mut T` +note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 59:8... + --> $DIR/missing-lifetimes-in-signature.rs:59:8 + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ^^ +note: ...so that return value is valid for the call + --> $DIR/missing-lifetimes-in-signature.rs:59:45 + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0309]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:69:44 + | +LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a + | - ^^^^^^^^^^^^^^^^^^ + | | + | help: consider adding an explicit lifetime bound...: `G: 'a` + | +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:74:5: 76:6 g:G, dest:&mut T]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:69:44 + | +LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0261, E0309, E0495. +For more information about an error, try `rustc --explain E0261`. From 99d9ccd5478c1cdfbe96216a59e3ce5b2e936278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 24 May 2020 11:52:12 -0700 Subject: [PATCH 470/695] Improve output of argument anonymous borrow missing annotation involving opaque return type Go from ``` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> file8.rs:22:5 | 22 | / move || { 23 | | *dest = g.get(); 24 | | } | |_____^ | note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 18:1... --> file8.rs:18:1 | 18 | / fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a 19 | | where 20 | | G: Get 21 | | { ... | 24 | | } 25 | | } | |_^ note: ...so that the types are compatible --> file8.rs:22:5 | 22 | / move || { //~ ERROR cannot infer an appropriate lifetime 23 | | *dest = g.get(); 24 | | } | |_____^ = note: expected `&mut T` found `&mut T` note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 18:8... --> file8.rs:18:8 | 18 | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | ^^ note: ...so that return value is valid for the call --> file8.rs:18:45 | 18 | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | ^^^^^^^^^^^^^^^^^^^^^^^ ``` to ``` error[E0621]: explicit lifetime required in the type of `dest` --> file8.rs:18:45 | 18 | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | ------ ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required | | | help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` ``` --- .../infer/error_reporting/mod.rs | 11 ++--- .../nice_region_error/named_anon_conflict.rs | 15 +++++-- .../missing-lifetimes-in-signature.rs | 4 +- .../missing-lifetimes-in-signature.stderr | 43 +++---------------- .../dyn-trait-underscore.nll.stderr | 7 +-- .../dyn-trait-underscore.rs | 2 +- .../dyn-trait-underscore.stderr | 31 +++---------- 7 files changed, 37 insertions(+), 76 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 3b98d47778fc1..a7b40d39215e2 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -1917,14 +1917,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "...", ); + debug!("report_sub_sup_conflict: var_origin={:?}", var_origin); + debug!("report_sub_sup_conflict: sub_region={:?}", sub_region); + debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin); + debug!("report_sub_sup_conflict: sup_region={:?}", sup_region); + debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin); + if let (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) { - debug!("report_sub_sup_conflict: var_origin={:?}", var_origin); - debug!("report_sub_sup_conflict: sub_region={:?}", sub_region); - debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin); - debug!("report_sub_sup_conflict: sup_region={:?}", sup_region); - debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin); debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace); debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace); debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values); diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index b85a4cae2e470..9da24138eeb03 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -74,13 +74,22 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let Some((_, fndecl)) = self.find_anon_type(anon, &br) { - if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() - || self.is_self_anon(is_first, scope_def_id) - { + let return_type_anon = self.is_return_type_anon(scope_def_id, br, fndecl); + let is_self_anon = self.is_self_anon(is_first, scope_def_id); + debug!( + "try_report_named_anon_conflict: fndecl {:?} {:?} {}", + fndecl, return_type_anon, is_self_anon + ); + if is_self_anon { + // We used to check for `return_type_anon.is_some()` here. Removing that improves + // some diagnostics, but we might have to readd the check if there are regressions + // in the wild. return None; } if let FnRetTy::Return(ty) = &fndecl.output { + debug!("try_report_named_anon_conflict: ret ty {:?}", ty); if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.kind, sub) { + debug!("try_report_named_anon_conflict: impl Trait + 'static"); // This is an impl Trait return that evaluates de need of 'static. // We handle this case better in `static_impl_trait`. return None; diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index b5f6fdeaa4ed0..589d04c9b1962 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -55,12 +55,12 @@ where } // After applying suggestion for `qux`: -// FIXME: we should suggest be suggesting to change `dest` to `&'a mut T`. fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a +//~^ ERROR explicit lifetime required in the type of `dest` where G: Get { - move || { //~ ERROR cannot infer an appropriate lifetime + move || { *dest = g.get(); } } diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index d69db90f3bacc..0326616337d6c 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -87,44 +87,13 @@ help: consider introducing an explicit lifetime bound to unify the type paramete LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b | ^^^ ^^^^^^^ ^^^^ -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/missing-lifetimes-in-signature.rs:63:5 - | -LL | / move || { -LL | | *dest = g.get(); -LL | | } - | |_____^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 59:1... - --> $DIR/missing-lifetimes-in-signature.rs:59:1 - | -LL | / fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a -LL | | where -LL | | G: Get -LL | | { -... | -LL | | } -LL | | } - | |_^ -note: ...so that the types are compatible - --> $DIR/missing-lifetimes-in-signature.rs:63:5 - | -LL | / move || { -LL | | *dest = g.get(); -LL | | } - | |_____^ - = note: expected `&mut T` - found `&mut T` -note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 59:8... - --> $DIR/missing-lifetimes-in-signature.rs:59:8 - | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ^^ -note: ...so that return value is valid for the call - --> $DIR/missing-lifetimes-in-signature.rs:59:45 +error[E0621]: explicit lifetime required in the type of `dest` + --> $DIR/missing-lifetimes-in-signature.rs:58:45 | LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ------ ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` error[E0309]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:69:44 @@ -142,5 +111,5 @@ LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a error: aborting due to 6 previous errors -Some errors have detailed explanations: E0261, E0309, E0495. +Some errors have detailed explanations: E0261, E0309, E0621. For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr index 8ed48bda26e85..a1f6c5386ae42 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr @@ -1,11 +1,12 @@ -error: lifetime may not live long enough +error[E0621]: explicit lifetime required in the type of `items` --> $DIR/dyn-trait-underscore.rs:8:5 | LL | fn a(items: &[T]) -> Box> { - | - let's call the lifetime of this reference `'1` + | ---- help: add explicit lifetime `'static` to the type of `items`: `&'static [T]` LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required error: aborting due to previous error +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs index d5aa18eb0f4e7..cd4781b8640c4 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs @@ -5,7 +5,7 @@ fn a(items: &[T]) -> Box> { // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` - Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime + Box::new(items.iter()) //~ ERROR explicit lifetime required in the type of `items` } fn b(items: &[T]) -> Box + '_> { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index e3c9d50dfe5b3..a1f6c5386ae42 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,31 +1,12 @@ -error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements - --> $DIR/dyn-trait-underscore.rs:8:20 - | -LL | Box::new(items.iter()) - | ^^^^ - | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 6:1... - --> $DIR/dyn-trait-underscore.rs:6:1 - | -LL | / fn a(items: &[T]) -> Box> { -LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` -LL | | Box::new(items.iter()) -LL | | } - | |_^ -note: ...so that reference does not outlive borrowed content - --> $DIR/dyn-trait-underscore.rs:8:14 - | -LL | Box::new(items.iter()) - | ^^^^^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable +error[E0621]: explicit lifetime required in the type of `items` --> $DIR/dyn-trait-underscore.rs:8:5 | +LL | fn a(items: &[T]) -> Box> { + | ---- help: add explicit lifetime `'static` to the type of `items`: `&'static [T]` +LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator + 'static)>` - found `std::boxed::Box>` + | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0621`. From a724d9a4fb1abade3754ffcd2c92bb755b7d5ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 24 May 2020 12:00:40 -0700 Subject: [PATCH 471/695] Fix NLL output --- .../missing-lifetimes-in-signature.nll.stderr | 98 +++++++++++++++++++ .../dyn-trait-underscore.nll.stderr | 12 --- 2 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr delete mode 100644 src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr new file mode 100644 index 0000000000000..f11c978aabf58 --- /dev/null +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr @@ -0,0 +1,98 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/missing-lifetimes-in-signature.rs:37:11 + | +LL | fn baz(g: G, dest: &mut T) -> impl FnOnce() + '_ + | - ^^ undeclared lifetime + | | + | help: consider introducing lifetime `'a` here: `'a,` + +error: lifetime may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:15:37 + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + | - ^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + | +help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a bound + | +LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:25:37 + | +LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 25:1... + --> $DIR/missing-lifetimes-in-signature.rs:25:1 + | +LL | / fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ +LL | | +LL | | where +LL | | G: Get +... | +LL | | } +LL | | } + | |_^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:47:45 + | +LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 47:1... + --> $DIR/missing-lifetimes-in-signature.rs:47:1 + | +LL | / fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ +LL | | +LL | | where +LL | | G: Get +... | +LL | | } +LL | | } + | |_^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:58:45 + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 58:1... + --> $DIR/missing-lifetimes-in-signature.rs:58:1 + | +LL | / fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a +LL | | +LL | | where +LL | | G: Get +... | +LL | | } +LL | | } + | |_^ + +error[E0621]: explicit lifetime required in the type of `dest` + --> $DIR/missing-lifetimes-in-signature.rs:63:5 + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` +... +LL | / move || { +LL | | *dest = g.get(); +LL | | } + | |_____^ lifetime `'a` required + +error[E0309]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:69:44 + | +LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `G: 'a`... + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0261, E0309, E0621. +For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr deleted file mode 100644 index a1f6c5386ae42..0000000000000 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0621]: explicit lifetime required in the type of `items` - --> $DIR/dyn-trait-underscore.rs:8:5 - | -LL | fn a(items: &[T]) -> Box> { - | ---- help: add explicit lifetime `'static` to the type of `items`: `&'static [T]` -LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` -LL | Box::new(items.iter()) - | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0621`. From 65f492be121ee9901d8c4305629cf4f2ad88f6d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 May 2020 13:13:19 -0700 Subject: [PATCH 472/695] Account for returned `dyn Trait` evaluating to `'static` lifetime Provide a suggestion for `dyn Trait + '_` when possible. --- .../error_reporting/nice_region_error/mod.rs | 2 +- .../nice_region_error/named_anon_conflict.rs | 38 ++----- .../nice_region_error/static_impl_trait.rs | 44 ++++---- src/librustc_middle/ty/context.rs | 101 +++++++++++++----- src/librustc_middle/ty/diagnostics.rs | 19 ++++ .../ui/async-await/issues/issue-62097.stderr | 2 +- .../must_outlive_least_region_or_bound.stderr | 18 ++-- .../static-return-lifetime-infered.stderr | 12 +-- src/test/ui/issues/issue-16922.rs | 2 +- src/test/ui/issues/issue-16922.stderr | 25 +++-- .../object-lifetime-default-from-box-error.rs | 2 +- ...ect-lifetime-default-from-box-error.stderr | 25 ++++- .../region-object-lifetime-in-coercion.rs | 9 +- .../region-object-lifetime-in-coercion.stderr | 40 ++++--- ...types_pin_lifetime_impl_trait-async.stderr | 2 +- ..._self_types_pin_lifetime_impl_trait.stderr | 6 +- .../missing-lifetimes-in-signature.stderr | 6 +- .../dyn-trait-underscore.rs | 2 +- .../dyn-trait-underscore.stderr | 26 +++-- 19 files changed, 239 insertions(+), 142 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs index efe52689550c4..cc8f1816bc3f4 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs @@ -55,9 +55,9 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { diag.emit(); ErrorReported }) + .or_else(|| self.try_report_impl_not_conforming_to_trait()) .or_else(|| self.try_report_anon_anon_conflict()) .or_else(|| self.try_report_static_impl_trait()) - .or_else(|| self.try_report_impl_not_conforming_to_trait()) } pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 9da24138eeb03..acaf474699276 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -21,8 +21,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // where the anonymous region appears (there must always be one; we // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced - // with the named one.//scope_def_id - let (named, anon, anon_param_info, region_info) = if self.is_named_region(sub) + // with the named one. + let (named, anon, anon_param_info, region_info) = if sub.has_name() && self.tcx().is_suitable_region(sup).is_some() && self.find_param_with_region(sup, sub).is_some() { @@ -32,7 +32,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { self.find_param_with_region(sup, sub).unwrap(), self.tcx().is_suitable_region(sup).unwrap(), ) - } else if self.is_named_region(sup) + } else if sup.has_name() && self.tcx().is_suitable_region(sub).is_some() && self.find_param_with_region(sub, sup).is_some() { @@ -74,24 +74,21 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let Some((_, fndecl)) = self.find_anon_type(anon, &br) { - let return_type_anon = self.is_return_type_anon(scope_def_id, br, fndecl); let is_self_anon = self.is_self_anon(is_first, scope_def_id); - debug!( - "try_report_named_anon_conflict: fndecl {:?} {:?} {}", - fndecl, return_type_anon, is_self_anon - ); if is_self_anon { - // We used to check for `return_type_anon.is_some()` here. Removing that improves - // some diagnostics, but we might have to readd the check if there are regressions - // in the wild. return None; } + if let FnRetTy::Return(ty) = &fndecl.output { + let mut v = ty::TraitObjectVisitor(vec![]); + rustc_hir::intravisit::walk_ty(&mut v, ty); + debug!("try_report_named_anon_conflict: ret ty {:?}", ty); - if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.kind, sub) { + if sub == &ty::ReStatic && (matches!(ty.kind, TyKind::Def(_, _)) || v.0.len() == 1) + { debug!("try_report_named_anon_conflict: impl Trait + 'static"); - // This is an impl Trait return that evaluates de need of 'static. - // We handle this case better in `static_impl_trait`. + // This is an `impl Trait` or `dyn Trait` return that evaluates de need of + // `'static`. We handle this case better in `static_impl_trait`. return None; } } @@ -123,17 +120,4 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { Some(diag) } - - // This method returns whether the given Region is Named - pub(super) fn is_named_region(&self, region: ty::Region<'tcx>) -> bool { - match *region { - ty::ReStatic => true, - ty::ReFree(ref free_region) => match free_region.bound_region { - ty::BrNamed(..) => true, - _ => false, - }, - ty::ReEarlyBound(ebr) => ebr.has_name(), - _ => false, - } - } } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 4ad587db0128d..1a8b7fda179b4 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -20,16 +20,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ) = error.clone() { let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; - let return_ty = self.tcx().return_type_impl_trait(anon_reg_sup.def_id); - if sub_r == &RegionKind::ReStatic && return_ty.is_some() { + let (fn_return_span, is_dyn) = + self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?; + if sub_r == &RegionKind::ReStatic { let sp = var_origin.span(); let return_sp = sub_origin.span(); let mut err = self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime"); - err.span_label( - return_sp, - "this return type evaluates to the `'static` lifetime...", - ); + err.span_label(return_sp, "this evaluates to the `'static` lifetime..."); err.span_label(sup_origin.span(), "...but this borrow..."); let (lifetime, lt_sp_opt) = msg_span_from_free_region(self.tcx(), sup_r); @@ -39,24 +37,22 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; - let fn_return_span = return_ty.unwrap().1; - if let Ok(snippet) = - self.tcx().sess.source_map().span_to_snippet(fn_return_span) - { - // only apply this suggestion onto functions with - // explicit non-desugar'able return. - if fn_return_span.desugaring_kind().is_none() { - err.span_suggestion( - fn_return_span, - &format!( - "you can add a bound to the return type to make it last less \ - than `'static` and match {}", - lifetime - ), - format!("{} + {}", snippet, lifetime_name), - Applicability::Unspecified, - ); - } + // only apply this suggestion onto functions with + // explicit non-desugar'able return. + if fn_return_span.desugaring_kind().is_none() { + let msg = format!( + "you can add a bound to the returned `{} Trait` to make it last less \ + than `'static` and match {}", + if is_dyn { "dyn" } else { "impl" }, + lifetime + ); + // FIXME: account for the need of parens in `&(dyn Trait + '_)` + err.span_suggestion_verbose( + fn_return_span.shrink_to_hi(), + &msg, + format!(" + {}", lifetime_name), + Applicability::MaybeIncorrect, + ); } err.emit(); return Some(ErrorReported); diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 3a08d202ea385..c9d240a5da91e 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1,38 +1,27 @@ //! Type context book-keeping. use crate::arena::Arena; -use crate::dep_graph::DepGraph; -use crate::dep_graph::{self, DepConstructor}; +use crate::dep_graph::{self, DepConstructor, DepGraph}; use crate::hir::exports::Export; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::lint::LintDiagnosticBuilder; -use crate::lint::{struct_lint_level, LintSource}; +use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintSource}; use crate::middle; -use crate::middle::cstore::CrateStoreDyn; -use crate::middle::cstore::EncodedMetadata; +use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata}; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use crate::middle::stability; -use crate::mir::interpret::{Allocation, ConstValue, Scalar}; -use crate::mir::{interpret, Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; +use crate::mir::interpret::{self, Allocation, ConstValue, Scalar}; +use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::traits; -use crate::ty::query; use crate::ty::steal::Steal; -use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; -use crate::ty::subst::{GenericArgKind, UserSubsts}; -use crate::ty::CanonicalPolyFnSig; -use crate::ty::GenericParamDefKind; -use crate::ty::RegionKind; -use crate::ty::ReprOptions; +use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; use crate::ty::TyKind::*; -use crate::ty::{self, DefIdTree, Ty, TypeAndMut}; -use crate::ty::{AdtDef, AdtKind, Const, Region}; -use crate::ty::{BindingMode, BoundVar}; -use crate::ty::{ConstVid, FloatVar, FloatVid, IntVar, IntVid, TyVar, TyVid}; -use crate::ty::{ExistentialPredicate, Predicate, PredicateKind}; -use crate::ty::{InferConst, ParamConst}; -use crate::ty::{InferTy, ParamTy, PolyFnSig, ProjectionTy}; -use crate::ty::{List, TyKind, TyS}; +use crate::ty::{ + self, query, AdtDef, AdtKind, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid, + DefIdTree, ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, + IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, ProjectionTy, + Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, +}; use rustc_ast::ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; @@ -48,10 +37,8 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathHash, Definitions}; -use rustc_hir::lang_items; -use rustc_hir::lang_items::PanicLocationLangItem; -use rustc_hir::{HirId, Node, TraitCandidate}; -use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet}; +use rustc_hir::lang_items::{self, PanicLocationLangItem}; +use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; @@ -1396,6 +1383,66 @@ impl<'tcx> TyCtxt<'tcx> { }) } + pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> { + let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local()); + let hir_output = match self.hir().get(hir_id) { + Node::Item(hir::Item { + kind: + ItemKind::Fn( + hir::FnSig { + decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, + .. + }, + .., + ), + .. + }) + | Node::ImplItem(hir::ImplItem { + kind: + hir::ImplItemKind::Fn( + hir::FnSig { + decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, + .. + }, + _, + ), + .. + }) + | Node::TraitItem(hir::TraitItem { + kind: + hir::TraitItemKind::Fn( + hir::FnSig { + decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, + .. + }, + _, + ), + .. + }) => ty, + _ => return None, + }; + + let ret_ty = self.type_of(scope_def_id); + match ret_ty.kind { + ty::FnDef(_, _) => { + let sig = ret_ty.fn_sig(*self); + let output = self.erase_late_bound_regions(&sig.output()); + if output.is_impl_trait() { + let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); + Some((fn_decl.output.span(), false)) + } else { + let mut v = TraitObjectVisitor(vec![]); + rustc_hir::intravisit::walk_ty(&mut v, hir_output); + if v.0.len() == 1 { + return Some((v.0[0], true)); + } + None + } + } + _ => None, + } + } + pub fn return_type_impl_trait(&self, scope_def_id: DefId) -> Option<(Ty<'tcx>, Span)> { // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local()); diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index 613d66d59c55b..1403efb745b15 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -249,3 +249,22 @@ pub fn suggest_constraining_type_param( true } } + +pub struct TraitObjectVisitor(pub Vec); +impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor { + type Map = rustc_hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + if let hir::TyKind::TraitObject( + _, + hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) = ty.kind + { + self.0.push(ty.span); + } + } +} diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 94afccc06a9e7..cd141b82e4125 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -4,7 +4,7 @@ error: cannot infer an appropriate lifetime LL | pub async fn run_dummy_fn(&self) { | ^^^^^ ...but this borrow... LL | foo(|| self.bar()).await; - | --- this return type evaluates to the `'static` lifetime... + | --- this evaluates to the `'static` lifetime... | note: ...can't outlive the lifetime `'_` as defined on the method body at 12:31 --> $DIR/issue-62097.rs:12:31 diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index cffa5ee8f1461..42667d6ca1a5d 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -4,17 +4,17 @@ error: cannot infer an appropriate lifetime LL | fn elided(x: &i32) -> impl Copy { x } | --------- ^ ...but this borrow... | | - | this return type evaluates to the `'static` lifetime... + | this evaluates to the `'static` lifetime... | note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1 --> $DIR/must_outlive_least_region_or_bound.rs:3:1 | LL | fn elided(x: &i32) -> impl Copy { x } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: you can add a bound to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1 +help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1 | LL | fn elided(x: &i32) -> impl Copy + '_ { x } - | ^^^^^^^^^^^^^^ + | ^^^^ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:6:44 @@ -22,17 +22,17 @@ error: cannot infer an appropriate lifetime LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | --------- ^ ...but this borrow... | | - | this return type evaluates to the `'static` lifetime... + | this evaluates to the `'static` lifetime... | note: ...can't outlive the lifetime `'a` as defined on the function body at 6:13 --> $DIR/must_outlive_least_region_or_bound.rs:6:13 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | ^^ -help: you can add a bound to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 6:13 +help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 6:13 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } - | ^^^^^^^^^^^^^^ + | ^^^^ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:12:69 @@ -40,17 +40,17 @@ error: cannot infer an appropriate lifetime LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -------------------------------- ^ ...but this borrow... | | - | this return type evaluates to the `'static` lifetime... + | this evaluates to the `'static` lifetime... | note: ...can't outlive the lifetime `'a` as defined on the function body at 12:15 --> $DIR/must_outlive_least_region_or_bound.rs:12:15 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | ^^ -help: you can add a bound to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 12:15 +help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 12:15 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error[E0623]: lifetime mismatch --> $DIR/must_outlive_least_region_or_bound.rs:17:61 diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index e550be1917474..963de2d448d7f 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -2,7 +2,7 @@ error: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator { - | ----------------------- this return type evaluates to the `'static` lifetime... + | ----------------------- this evaluates to the `'static` lifetime... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | @@ -15,16 +15,16 @@ LL | / fn iter_values_anon(&self) -> impl Iterator { LL | | self.x.iter().map(|a| a.0) LL | | } | |_____^ -help: you can add a bound to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 6:5 +help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 6:5 | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:11:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { - | ----------------------- this return type evaluates to the `'static` lifetime... + | ----------------------- this evaluates to the `'static` lifetime... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | @@ -35,10 +35,10 @@ note: ...can't outlive the lifetime `'a` as defined on the method body at 10:20 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { | ^^ -help: you can add a bound to the return type to make it last less than `'static` and match the lifetime `'a` as defined on the method body at 10:20 +help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the lifetime `'a` as defined on the method body at 10:20 | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-16922.rs b/src/test/ui/issues/issue-16922.rs index 10a5cccbceef0..827163ef83cf7 100644 --- a/src/test/ui/issues/issue-16922.rs +++ b/src/test/ui/issues/issue-16922.rs @@ -2,7 +2,7 @@ use std::any::Any; fn foo(value: &T) -> Box { Box::new(value) as Box - //~^ ERROR explicit lifetime required in the type of `value` [E0621] + //~^ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 4e3d3ecb9c03a..8bcfe979ce145 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -1,11 +1,24 @@ -error[E0621]: explicit lifetime required in the type of `value` - --> $DIR/issue-16922.rs:4:5 +error: cannot infer an appropriate lifetime + --> $DIR/issue-16922.rs:4:14 | -LL | fn foo(value: &T) -> Box { - | -- help: add explicit lifetime `'static` to the type of `value`: `&'static T` LL | Box::new(value) as Box - | ^^^^^^^^^^^^^^^ lifetime `'static` required + | ---------^^^^^- + | | | + | | ...but this borrow... + | this evaluates to the `'static` lifetime... + | +note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1 + --> $DIR/issue-16922.rs:3:1 + | +LL | / fn foo(value: &T) -> Box { +LL | | Box::new(value) as Box +LL | | +LL | | } + | |_^ +help: you can add a bound to the returned `dyn Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1 + | +LL | fn foo(value: &T) -> Box { + | ^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs index 587aab1edce38..708ab1cf38297 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.rs @@ -15,7 +15,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR explicit lifetime required in the type of `ss` [E0621] + ss.r //~ ERROR cannot infer an appropriate lifetime } fn store(ss: &mut SomeStruct, b: Box) { diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 78e4bdd374da9..7981d082c8008 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -1,11 +1,26 @@ -error[E0621]: explicit lifetime required in the type of `ss` +error: cannot infer an appropriate lifetime --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | -LL | fn load(ss: &mut SomeStruct) -> Box { - | --------------- help: add explicit lifetime `'static` to the type of `ss`: `&mut SomeStruct<'static>` -... LL | ss.r - | ^^^^ lifetime `'static` required + | ^^^^ + | | + | this evaluates to the `'static` lifetime... + | ...but this borrow... + | +note: ...can't outlive the anonymous lifetime #2 defined on the function body at 14:1 + --> $DIR/object-lifetime-default-from-box-error.rs:14:1 + | +LL | / fn load(ss: &mut SomeStruct) -> Box { +LL | | // `Box` defaults to a `'static` bound, so this return +LL | | // is illegal. +LL | | +LL | | ss.r +LL | | } + | |_^ +help: you can add a bound to the returned `dyn Trait` to make it last less than `'static` and match the anonymous lifetime #2 defined on the function body at 14:1 + | +LL | fn load(ss: &mut SomeStruct) -> Box { + | ^^^^ error[E0621]: explicit lifetime required in the type of `ss` --> $DIR/object-lifetime-default-from-box-error.rs:31:12 diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.rs b/src/test/ui/regions/region-object-lifetime-in-coercion.rs index 2dc67599913a6..d56eaf77b6646 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.rs +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.rs @@ -11,20 +11,17 @@ fn a(v: &[u8]) -> Box { } fn b(v: &[u8]) -> Box { - Box::new(v) - //~^ ERROR explicit lifetime required in the type of `v` [E0621] + Box::new(v) //~ ERROR explicit lifetime required in the type of `v` [E0621] } fn c(v: &[u8]) -> Box { // same as previous case due to RFC 599 - Box::new(v) - //~^ ERROR explicit lifetime required in the type of `v` [E0621] + Box::new(v) //~ ERROR cannot infer an appropriate lifetime } fn d<'a,'b>(v: &'a [u8]) -> Box { - Box::new(v) - //~^ ERROR cannot infer an appropriate lifetime due to conflicting + Box::new(v) //~ ERROR cannot infer an appropriate lifetime due to conflicting } fn e<'a:'b,'b>(v: &'a [u8]) -> Box { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 069b897603cb9..8048b79b015d5 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -14,40 +14,54 @@ LL | fn b(v: &[u8]) -> Box { LL | Box::new(v) | ^^^^^^^^^^^ lifetime `'static` required -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:21:5 +error: cannot infer an appropriate lifetime + --> $DIR/region-object-lifetime-in-coercion.rs:20:14 | -LL | fn c(v: &[u8]) -> Box { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` -... LL | Box::new(v) - | ^^^^^^^^^^^ lifetime `'static` required + | ---------^- + | | | + | | ...but this borrow... + | this evaluates to the `'static` lifetime... + | +note: ...can't outlive the anonymous lifetime #1 defined on the function body at 17:1 + --> $DIR/region-object-lifetime-in-coercion.rs:17:1 + | +LL | / fn c(v: &[u8]) -> Box { +LL | | // same as previous case due to RFC 599 +LL | | +LL | | Box::new(v) +LL | | } + | |_^ +help: you can add a bound to the returned `dyn Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 17:1 + | +LL | fn c(v: &[u8]) -> Box { + | ^^^^ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/region-object-lifetime-in-coercion.rs:26:14 + --> $DIR/region-object-lifetime-in-coercion.rs:24:14 | LL | Box::new(v) | ^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 25:6... - --> $DIR/region-object-lifetime-in-coercion.rs:25:6 +note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 23:6... + --> $DIR/region-object-lifetime-in-coercion.rs:23:6 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | ^^ note: ...so that the expression is assignable - --> $DIR/region-object-lifetime-in-coercion.rs:26:14 + --> $DIR/region-object-lifetime-in-coercion.rs:24:14 | LL | Box::new(v) | ^ = note: expected `&[u8]` found `&'a [u8]` -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 25:9... - --> $DIR/region-object-lifetime-in-coercion.rs:25:9 +note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 23:9... + --> $DIR/region-object-lifetime-in-coercion.rs:23:9 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | ^^ note: ...so that the expression is assignable - --> $DIR/region-object-lifetime-in-coercion.rs:26:5 + --> $DIR/region-object-lifetime-in-coercion.rs:24:5 | LL | Box::new(v) | ^^^^^^^^^^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 91075ffbdb605..fcde3bb5ca651 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -2,7 +2,7 @@ error: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^ ---------- this return type evaluates to the `'static` lifetime... + | ^^^^ ---------- this evaluates to the `'static` lifetime... | | | ...but this borrow... | diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 47ab6fff83878..c89ee27aa8cd7 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -4,17 +4,17 @@ error: cannot infer an appropriate lifetime LL | fn f(self: Pin<&Self>) -> impl Clone { self } | ---------- ^^^^ ...but this borrow... | | - | this return type evaluates to the `'static` lifetime... + | this evaluates to the `'static` lifetime... | note: ...can't outlive the anonymous lifetime #1 defined on the method body at 6:5 --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:5 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: you can add a bound to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 6:5 +help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 6:5 | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } - | ^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 0326616337d6c..5a2530bdcbb20 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -10,7 +10,7 @@ error: cannot infer an appropriate lifetime --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | ------------- this return type evaluates to the `'static` lifetime... + | ------------- this evaluates to the `'static` lifetime... ... LL | / move || { LL | | *dest = g.get(); @@ -28,10 +28,10 @@ LL | | { LL | | } LL | | } | |_^ -help: you can add a bound to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 15:1 +help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 15:1 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ^^^^^^^^^^^^^^^^^^ + | ^^^^ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:25:37 diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs index cd4781b8640c4..d5aa18eb0f4e7 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs @@ -5,7 +5,7 @@ fn a(items: &[T]) -> Box> { // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` - Box::new(items.iter()) //~ ERROR explicit lifetime required in the type of `items` + Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime } fn b(items: &[T]) -> Box + '_> { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index a1f6c5386ae42..65714d16a81dd 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,12 +1,24 @@ -error[E0621]: explicit lifetime required in the type of `items` - --> $DIR/dyn-trait-underscore.rs:8:5 +error: cannot infer an appropriate lifetime + --> $DIR/dyn-trait-underscore.rs:8:20 | -LL | fn a(items: &[T]) -> Box> { - | ---- help: add explicit lifetime `'static` to the type of `items`: `&'static [T]` -LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required + | ---------------^^^^--- + | | | + | | ...but this borrow... + | this evaluates to the `'static` lifetime... + | +note: ...can't outlive the anonymous lifetime #1 defined on the function body at 6:1 + --> $DIR/dyn-trait-underscore.rs:6:1 + | +LL | / fn a(items: &[T]) -> Box> { +LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` +LL | | Box::new(items.iter()) +LL | | } + | |_^ +help: you can add a bound to the returned `dyn Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 6:1 + | +LL | fn a(items: &[T]) -> Box + '_> { + | ^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0621`. From 731ea85f215f03fc33a92147d6cc51a01dee589f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 May 2020 17:20:08 -0700 Subject: [PATCH 473/695] review comment: tweak wording and account for span overlap --- .../infer/error_reporting/mod.rs | 3 +-- .../nice_region_error/static_impl_trait.rs | 19 +++++++++++++++++-- .../ui/async-await/issues/issue-62097.stderr | 2 +- .../must_outlive_least_region_or_bound.stderr | 6 +++--- .../static-return-lifetime-infered.stderr | 4 ++-- src/test/ui/issues/issue-16922.stderr | 2 +- ...ect-lifetime-default-from-box-error.stderr | 5 +---- .../region-object-lifetime-in-coercion.stderr | 2 +- ...types_pin_lifetime_impl_trait-async.stderr | 2 +- ..._self_types_pin_lifetime_impl_trait.stderr | 2 +- .../missing-lifetimes-in-signature.stderr | 6 +++--- .../dyn-trait-underscore.stderr | 10 ++++++---- 12 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index a7b40d39215e2..d00c90d06e4c1 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -1806,8 +1806,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { |err: &mut DiagnosticBuilder<'tcx>, type_param_span: Option<(Span, bool, bool)>, bound_kind: GenericKind<'tcx>| { - let msg = "consider introducing an explicit lifetime bound to unify the type \ - parameter and the output"; + let msg = "consider introducing an explicit lifetime bound"; if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span { let suggestion = if is_impl_trait { (sp.shrink_to_hi(), format!(" + {}", new_lt)) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 1a8b7fda179b4..5c5c86a4fb118 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -27,8 +27,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let return_sp = sub_origin.span(); let mut err = self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime"); - err.span_label(return_sp, "this evaluates to the `'static` lifetime..."); - err.span_label(sup_origin.span(), "...but this borrow..."); + if sp == sup_origin.span() && return_sp == sp { + // Example: `ui/object-lifetime/object-lifetime-default-from-box-error.rs` + err.span_label( + sup_origin.span(), + "this needs to be `'static` but the borrow...", + ); + } else { + err.span_label(return_sp, "this is `'static`..."); + // We try to make the output have fewer overlapping spans if possible. + if sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()) { + // When `sp == sup_origin` we already have overlapping spans in the + // main diagnostic output, so we don't split this into its own note. + err.span_label(sup_origin.span(), "...but this borrow..."); + } else { + err.span_note(sup_origin.span(), "...but this borrow..."); + } + } let (lifetime, lt_sp_opt) = msg_span_from_free_region(self.tcx(), sup_r); if let Some(lifetime_sp) = lt_sp_opt { diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index cd141b82e4125..161b2565c3dfc 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -4,7 +4,7 @@ error: cannot infer an appropriate lifetime LL | pub async fn run_dummy_fn(&self) { | ^^^^^ ...but this borrow... LL | foo(|| self.bar()).await; - | --- this evaluates to the `'static` lifetime... + | --- this is `'static`... | note: ...can't outlive the lifetime `'_` as defined on the method body at 12:31 --> $DIR/issue-62097.rs:12:31 diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 42667d6ca1a5d..9d068d70bd488 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -4,7 +4,7 @@ error: cannot infer an appropriate lifetime LL | fn elided(x: &i32) -> impl Copy { x } | --------- ^ ...but this borrow... | | - | this evaluates to the `'static` lifetime... + | this is `'static`... | note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1 --> $DIR/must_outlive_least_region_or_bound.rs:3:1 @@ -22,7 +22,7 @@ error: cannot infer an appropriate lifetime LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | --------- ^ ...but this borrow... | | - | this evaluates to the `'static` lifetime... + | this is `'static`... | note: ...can't outlive the lifetime `'a` as defined on the function body at 6:13 --> $DIR/must_outlive_least_region_or_bound.rs:6:13 @@ -40,7 +40,7 @@ error: cannot infer an appropriate lifetime LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -------------------------------- ^ ...but this borrow... | | - | this evaluates to the `'static` lifetime... + | this is `'static`... | note: ...can't outlive the lifetime `'a` as defined on the function body at 12:15 --> $DIR/must_outlive_least_region_or_bound.rs:12:15 diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index 963de2d448d7f..645c7e1e1954c 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -2,7 +2,7 @@ error: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator { - | ----------------------- this evaluates to the `'static` lifetime... + | ----------------------- this is `'static`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | @@ -24,7 +24,7 @@ error: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:11:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { - | ----------------------- this evaluates to the `'static` lifetime... + | ----------------------- this is `'static`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 8bcfe979ce145..20a6b287429f9 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -5,7 +5,7 @@ LL | Box::new(value) as Box | ---------^^^^^- | | | | | ...but this borrow... - | this evaluates to the `'static` lifetime... + | this is `'static`... | note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1 --> $DIR/issue-16922.rs:3:1 diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 7981d082c8008..465409c639891 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -2,10 +2,7 @@ error: cannot infer an appropriate lifetime --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | ss.r - | ^^^^ - | | - | this evaluates to the `'static` lifetime... - | ...but this borrow... + | ^^^^ this needs to be `'static` but the borrow... | note: ...can't outlive the anonymous lifetime #2 defined on the function body at 14:1 --> $DIR/object-lifetime-default-from-box-error.rs:14:1 diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 8048b79b015d5..5a414c477a69f 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -21,7 +21,7 @@ LL | Box::new(v) | ---------^- | | | | | ...but this borrow... - | this evaluates to the `'static` lifetime... + | this is `'static`... | note: ...can't outlive the anonymous lifetime #1 defined on the function body at 17:1 --> $DIR/region-object-lifetime-in-coercion.rs:17:1 diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index fcde3bb5ca651..21775539cea76 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -2,7 +2,7 @@ error: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^ ---------- this evaluates to the `'static` lifetime... + | ^^^^ ---------- this is `'static`... | | | ...but this borrow... | diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index c89ee27aa8cd7..e931cec8a2a84 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -4,7 +4,7 @@ error: cannot infer an appropriate lifetime LL | fn f(self: Pin<&Self>) -> impl Clone { self } | ---------- ^^^^ ...but this borrow... | | - | this evaluates to the `'static` lifetime... + | this is `'static`... | note: ...can't outlive the anonymous lifetime #1 defined on the method body at 6:5 --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:5 diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 5a2530bdcbb20..d6d2a0c4d2b63 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -10,7 +10,7 @@ error: cannot infer an appropriate lifetime --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | ------------- this evaluates to the `'static` lifetime... + | ------------- this is `'static`... ... LL | / move || { LL | | *dest = g.get(); @@ -55,7 +55,7 @@ note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: | LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^^^^^^^^^^^^^^^ -help: consider introducing an explicit lifetime bound to unify the type parameter and the output +help: consider introducing an explicit lifetime bound | LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | ^^^^^ ^^^^ @@ -82,7 +82,7 @@ note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: | LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^^^^^^^^^^^^^^^ -help: consider introducing an explicit lifetime bound to unify the type parameter and the output +help: consider introducing an explicit lifetime bound | LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b | ^^^ ^^^^^^^ ^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 65714d16a81dd..bcbdec4f306d9 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -2,11 +2,13 @@ error: cannot infer an appropriate lifetime --> $DIR/dyn-trait-underscore.rs:8:20 | LL | Box::new(items.iter()) - | ---------------^^^^--- - | | | - | | ...but this borrow... - | this evaluates to the `'static` lifetime... + | ---------------^^^^--- this is `'static`... | +note: ...but this borrow... + --> $DIR/dyn-trait-underscore.rs:8:14 + | +LL | Box::new(items.iter()) + | ^^^^^ note: ...can't outlive the anonymous lifetime #1 defined on the function body at 6:1 --> $DIR/dyn-trait-underscore.rs:6:1 | From 1d9472b4700ed64a42cf8000d182152255bce1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 26 May 2020 17:22:47 -0700 Subject: [PATCH 474/695] Update nll tests --- src/test/ui/issues/issue-16922.nll.stderr | 10 ++++++++++ .../object-lifetime-default-from-box-error.nll.stderr | 6 +++--- .../region-object-lifetime-in-coercion.nll.stderr | 10 +++++----- .../dyn-trait-underscore.nll.stderr | 11 +++++++++++ 4 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/issues/issue-16922.nll.stderr create mode 100644 src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr diff --git a/src/test/ui/issues/issue-16922.nll.stderr b/src/test/ui/issues/issue-16922.nll.stderr new file mode 100644 index 0000000000000..7f4f5b22eb302 --- /dev/null +++ b/src/test/ui/issues/issue-16922.nll.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/issue-16922.rs:4:5 + | +LL | fn foo(value: &T) -> Box { + | - let's call the lifetime of this reference `'1` +LL | Box::new(value) as Box + | ^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr index f6252f4ed7977..9563c0dff3644 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr @@ -1,11 +1,11 @@ -error[E0621]: explicit lifetime required in the type of `ss` +error: lifetime may not live long enough --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | fn load(ss: &mut SomeStruct) -> Box { - | --------------- help: add explicit lifetime `'static` to the type of `ss`: `&mut SomeStruct<'static>` + | -- has type `&mut SomeStruct<'1>` ... LL | ss.r - | ^^^^ lifetime `'static` required + | ^^^^ returning this value requires that `'1` must outlive `'static` error[E0507]: cannot move out of `ss.r` which is behind a mutable reference --> $DIR/object-lifetime-default-from-box-error.rs:18:5 diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr index 767853d81480e..bf02ba8eb9199 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr @@ -14,17 +14,17 @@ LL | fn b(v: &[u8]) -> Box { LL | Box::new(v) | ^^^^^^^^^^^ lifetime `'static` required -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:21:5 +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-in-coercion.rs:20:5 | LL | fn c(v: &[u8]) -> Box { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | - let's call the lifetime of this reference `'1` ... LL | Box::new(v) - | ^^^^^^^^^^^ lifetime `'static` required + | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough - --> $DIR/region-object-lifetime-in-coercion.rs:26:5 + --> $DIR/region-object-lifetime-in-coercion.rs:24:5 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box { | -- -- lifetime `'b` defined here diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr new file mode 100644 index 0000000000000..8ed48bda26e85 --- /dev/null +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/dyn-trait-underscore.rs:8:5 + | +LL | fn a(items: &[T]) -> Box> { + | - let's call the lifetime of this reference `'1` +LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` +LL | Box::new(items.iter()) + | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + +error: aborting due to previous error + From 8f7ee34379240e7c29c7dda867905e2d0044bde1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 27 May 2020 11:15:58 -0700 Subject: [PATCH 475/695] Tweak type parameter errors to reduce verbosity --- .../infer/error_reporting/note.rs | 34 ++++++++----- .../builtin-superkinds-self-type.stderr | 8 +--- ...-infer_static_outlives_requirements.stderr | 8 +--- .../impl_bounds.stderr | 6 +-- .../must_outlive_least_region_or_bound.stderr | 8 +--- .../type_parameters_captured.stderr | 8 +--- .../lifetime-doesnt-live-long-enough.stderr | 46 +++--------------- ...ection-where-clause-env-wrong-bound.stderr | 6 +-- ...ion-where-clause-env-wrong-lifetime.stderr | 6 +-- ...s-close-associated-type-into-object.stderr | 24 ++-------- .../regions-close-object-into-object-5.stderr | 48 +++---------------- ...regions-close-over-type-parameter-1.stderr | 16 +------ .../regions-close-param-into-object.stderr | 32 ++----------- .../ui/regions/regions-enum-not-wf.stderr | 35 ++------------ ...ons-implied-bounds-projection-gap-1.stderr | 8 +--- ...regions-infer-bound-from-trait-self.stderr | 6 +-- .../regions-infer-bound-from-trait.stderr | 16 +------ .../dont-infer-static.stderr | 8 +--- .../regions-enum-not-wf.stderr | 35 ++------------ .../regions-struct-not-wf.stderr | 16 +------ .../missing-lifetimes-in-signature.stderr | 8 +--- .../suggest-impl-trait-lifetime.stderr | 8 +--- ...eric_type_does_not_live_long_enough.stderr | 8 +--- .../wf/wf-impl-associated-type-region.stderr | 8 +--- src/test/ui/wf/wf-in-fn-type-static.stderr | 16 +------ src/test/ui/wf/wf-in-obj-type-static.stderr | 8 +--- .../wf/wf-outlives-ty-in-fn-or-trait.stderr | 16 +------ .../wf/wf-trait-associated-type-region.stderr | 6 +-- 28 files changed, 78 insertions(+), 374 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/note.rs b/src/librustc_infer/infer/error_reporting/note.rs index 968c488bc004e..9ac27030adeea 100644 --- a/src/librustc_infer/infer/error_reporting/note.rs +++ b/src/librustc_infer/infer/error_reporting/note.rs @@ -10,10 +10,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, origin: &SubregionOrigin<'tcx>, ) { + let mut label_or_note = |span, msg| { + let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count(); + let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count(); + let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span); + if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { + err.span_label(span, msg); + } else if span_is_primary && expanded_sub_count == 0 { + err.note(msg); + } else { + err.span_note(span, msg); + } + }; match *origin { infer::Subtype(ref trace) => { if let Some((expected, found)) = self.values_str(&trace.values) { - err.span_note( + label_or_note( trace.cause.span, &format!("...so that the {}", trace.cause.as_requirement_str()), ); @@ -24,27 +36,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // handling of region checking when type errors are present is // *terrible*. - err.span_note( + label_or_note( trace.cause.span, &format!("...so that {}", trace.cause.as_requirement_str()), ); } } infer::Reborrow(span) => { - err.span_note(span, "...so that reference does not outlive borrowed content"); + label_or_note(span, "...so that reference does not outlive borrowed content"); } infer::ReborrowUpvar(span, ref upvar_id) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - err.span_note(span, &format!("...so that closure can access `{}`", var_name)); + label_or_note(span, &format!("...so that closure can access `{}`", var_name)); } infer::RelateObjectBound(span) => { - err.span_note(span, "...so that it can be closed over into an object"); + label_or_note(span, "...so that it can be closed over into an object"); } infer::CallReturn(span) => { - err.span_note(span, "...so that return value is valid for the call"); + label_or_note(span, "...so that return value is valid for the call"); } infer::DataBorrowed(ty, span) => { - err.span_note( + label_or_note( span, &format!( "...so that the type `{}` is not borrowed for too long", @@ -53,7 +65,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } infer::ReferenceOutlivesReferent(ty, span) => { - err.span_note( + label_or_note( span, &format!( "...so that the reference type `{}` does not outlive the data it points at", @@ -62,7 +74,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } infer::RelateParamBound(span, t) => { - err.span_note( + label_or_note( span, &format!( "...so that the type `{}` will meet its required lifetime bounds", @@ -71,13 +83,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } infer::RelateRegionParamBound(span) => { - err.span_note( + label_or_note( span, "...so that the declared lifetime parameter bounds are satisfied", ); } infer::CompareImplMethodObligation { span, .. } => { - err.span_note( + label_or_note( span, "...so that the definition in impl matches the definition from the trait", ); diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr index 999a5839ba690..2dac4a22ae713 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr @@ -2,15 +2,9 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/builtin-superkinds-self-type.rs:10:16 | LL | impl Foo for T { } - | -- ^^^ + | -- ^^^ ...so that the type `T` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `T: 'static +` - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/builtin-superkinds-self-type.rs:10:16 - | -LL | impl Foo for T { } - | ^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr index fbc4e8abc42fd..2beeba8184a7d 100644 --- a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr +++ b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr @@ -4,13 +4,7 @@ error[E0310]: the parameter type `U` may not live long enough LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar - | ^^^^^^^^^^^ - | -note: ...so that the type `U` will meet its required lifetime bounds - --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:5 - | -LL | bar: Bar - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index d5560c8133773..e06977ebbe3df 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -5,11 +5,7 @@ LL | type A<'a> where Self: 'static = (&'a ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... -note: ...so that the type `Fooy` will meet its required lifetime bounds - --> $DIR/impl_bounds.rs:15:5 - | -LL | type A<'a> where Self: 'static = (&'a ()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...so that the type `Fooy` will meet its required lifetime bounds error[E0478]: lifetime bound not satisfied --> $DIR/impl_bounds.rs:17:5 diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 9d068d70bd488..0079fabb58d33 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -65,15 +65,9 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:22:51 | LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { - | -- ^^^^^^^^^^^^^^^^^^^^ + | -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `T: 'static +` - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/must_outlive_least_region_or_bound.rs:22:51 - | -LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/impl-trait/type_parameters_captured.stderr b/src/test/ui/impl-trait/type_parameters_captured.stderr index 34f0f7f1d731c..40e50b9922f8d 100644 --- a/src/test/ui/impl-trait/type_parameters_captured.stderr +++ b/src/test/ui/impl-trait/type_parameters_captured.stderr @@ -2,15 +2,9 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/type_parameters_captured.rs:7:20 | LL | fn foo(x: T) -> impl Any + 'static { - | - ^^^^^^^^^^^^^^^^^^ + | - ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `T: 'static` - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/type_parameters_captured.rs:7:20 - | -LL | fn foo(x: T) -> impl Any + 'static { - | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr index e60c461743c8f..d682478db0eef 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -4,13 +4,7 @@ error[E0310]: the parameter type `T` may not live long enough LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | foo: &'static T - | ^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'static T` does not outlive the data it points at - --> $DIR/lifetime-doesnt-live-long-enough.rs:19:5 - | -LL | foo: &'static T - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19 @@ -18,13 +12,7 @@ error[E0309]: the parameter type `K` may not live long enough LL | trait X: Sized { | - help: consider adding an explicit lifetime bound...: `K: 'a` LL | fn foo<'a, L: X<&'a Nested>>(); - | ^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'a Nested` does not outlive the data it points at - --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19 - | -LL | fn foo<'a, L: X<&'a Nested>>(); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at error[E0309]: the parameter type `Self` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:28:19 @@ -33,25 +21,15 @@ LL | fn bar<'a, L: X<&'a Nested>>(); | ^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `Self: 'a`... -note: ...so that the reference type `&'a Nested` does not outlive the data it points at - --> $DIR/lifetime-doesnt-live-long-enough.rs:28:19 - | -LL | fn bar<'a, L: X<&'a Nested>>(); - | ^^^^^^^^^^^^^^^^^^^ + = note: ...so that the reference type `&'a Nested` does not outlive the data it points at error[E0309]: the parameter type `L` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:32:22 | LL | fn baz<'a, L, M: X<&'a Nested>>() { - | - ^^^^^^^^^^^^^^^^ + | - ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at | | | help: consider adding an explicit lifetime bound...: `L: 'a` - | -note: ...so that the reference type `&'a Nested` does not outlive the data it points at - --> $DIR/lifetime-doesnt-live-long-enough.rs:32:22 - | -LL | fn baz<'a, L, M: X<&'a Nested>>() { - | ^^^^^^^^^^^^^^^^ error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33 @@ -59,25 +37,15 @@ error[E0309]: the parameter type `K` may not live long enough LL | impl Nested { | - help: consider adding an explicit lifetime bound...: `K: 'a` LL | fn generic_in_parent<'a, L: X<&'a Nested>>() { - | ^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'a Nested` does not outlive the data it points at - --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33 - | -LL | fn generic_in_parent<'a, L: X<&'a Nested>>() { - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at error[E0309]: the parameter type `M` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36 | LL | fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b>() { | ^^^^^^^^^^^^^^^^ -- help: consider adding an explicit lifetime bound...: `M: 'a +` - | -note: ...so that the reference type `&'a Nested` does not outlive the data it points at - --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36 - | -LL | fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b>() { - | ^^^^^^^^^^^^^^^^ + | | + | ...so that the reference type `&'a Nested` does not outlive the data it points at error: aborting due to 6 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr index 1a5a3719fd86d..eba00c5a9454e 100644 --- a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr @@ -5,11 +5,7 @@ LL | bar::() | ^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `>::Output: 'a`... -note: ...so that the type `>::Output` will meet its required lifetime bounds - --> $DIR/projection-where-clause-env-wrong-bound.rs:15:5 - | -LL | bar::() - | ^^^^^^^^^^^^^^^^ + = note: ...so that the type `>::Output` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr index d6ade2a603e82..34b83859a6bd2 100644 --- a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-lifetime.stderr @@ -5,11 +5,7 @@ LL | bar::<>::Output>() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `>::Output: 'a`... -note: ...so that the type `>::Output` will meet its required lifetime bounds - --> $DIR/projection-where-clause-env-wrong-lifetime.rs:14:5 - | -LL | bar::<>::Output>() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...so that the type `>::Output` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.stderr index 2401f549a5604..9303e0f8e6643 100644 --- a/src/test/ui/regions/regions-close-associated-type-into-object.stderr +++ b/src/test/ui/regions/regions-close-associated-type-into-object.stderr @@ -5,11 +5,7 @@ LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'static`... -note: ...so that the type `::Item` will meet its required lifetime bounds - --> $DIR/regions-close-associated-type-into-object.rs:15:5 - | -LL | Box::new(item) - | ^^^^^^^^^^^^^^ + = note: ...so that the type `::Item` will meet its required lifetime bounds error[E0310]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:22:5 @@ -18,11 +14,7 @@ LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'static`... -note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds - --> $DIR/regions-close-associated-type-into-object.rs:22:5 - | -LL | Box::new(item) - | ^^^^^^^^^^^^^^ + = note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds error[E0309]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:28:5 @@ -31,11 +23,7 @@ LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'a`... -note: ...so that the type `::Item` will meet its required lifetime bounds - --> $DIR/regions-close-associated-type-into-object.rs:28:5 - | -LL | Box::new(item) - | ^^^^^^^^^^^^^^ + = note: ...so that the type `::Item` will meet its required lifetime bounds error[E0309]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:35:5 @@ -44,11 +32,7 @@ LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'a`... -note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds - --> $DIR/regions-close-associated-type-into-object.rs:35:5 - | -LL | Box::new(item) - | ^^^^^^^^^^^^^^ + = note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-close-object-into-object-5.stderr b/src/test/ui/regions/regions-close-object-into-object-5.stderr index 2bcdcd1864e2f..e5a80cbd54758 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-5.stderr @@ -5,13 +5,7 @@ LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box - | ^^^^^^^^^^ - | -note: ...so that the type `B<'_, T>` will meet its required lifetime bounds - --> $DIR/regions-close-object-into-object-5.rs:17:5 - | -LL | box B(&*v) as Box - | ^^^^^^^^^^ + | ^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:9 @@ -20,13 +14,7 @@ LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box - | ^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-close-object-into-object-5.rs:17:9 - | -LL | box B(&*v) as Box - | ^ + | ^ ...so that the type `T` will meet its required lifetime bounds error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:9 @@ -35,13 +23,7 @@ LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box - | ^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-close-object-into-object-5.rs:17:9 - | -LL | box B(&*v) as Box - | ^^^^^^ + | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 @@ -50,13 +32,7 @@ LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box - | ^^^ - | -note: ...so that the reference type `&dyn A` does not outlive the data it points at - --> $DIR/regions-close-object-into-object-5.rs:17:11 - | -LL | box B(&*v) as Box - | ^^^ + | ^^^ ...so that the reference type `&dyn A` does not outlive the data it points at error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 @@ -65,13 +41,7 @@ LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box - | ^^^ - | -note: ...so that the type `(dyn A + 'static)` is not borrowed for too long - --> $DIR/regions-close-object-into-object-5.rs:17:11 - | -LL | box B(&*v) as Box - | ^^^ + | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 @@ -80,13 +50,7 @@ LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box - | ^^^ - | -note: ...so that the type `(dyn A + 'static)` is not borrowed for too long - --> $DIR/regions-close-object-into-object-5.rs:17:11 - | -LL | box B(&*v) as Box - | ^^^ + | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long error: aborting due to 6 previous errors diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr index a7509cb608c6b..50274b066df60 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr @@ -4,13 +4,7 @@ error[E0310]: the parameter type `A` may not live long enough LL | fn make_object1(v: A) -> Box { | -- help: consider adding an explicit lifetime bound...: `A: 'static +` LL | box v as Box - | ^^^^^ - | -note: ...so that the type `A` will meet its required lifetime bounds - --> $DIR/regions-close-over-type-parameter-1.rs:12:5 - | -LL | box v as Box - | ^^^^^ + | ^^^^^ ...so that the type `A` will meet its required lifetime bounds error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:21:5 @@ -18,13 +12,7 @@ error[E0309]: the parameter type `A` may not live long enough LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { | -- help: consider adding an explicit lifetime bound...: `A: 'b +` LL | box v as Box - | ^^^^^ - | -note: ...so that the type `A` will meet its required lifetime bounds - --> $DIR/regions-close-over-type-parameter-1.rs:21:5 - | -LL | box v as Box - | ^^^^^ + | ^^^^^ ...so that the type `A` will meet its required lifetime bounds error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-close-param-into-object.stderr b/src/test/ui/regions/regions-close-param-into-object.stderr index 3b1a89d9ced77..705d21078ecd7 100644 --- a/src/test/ui/regions/regions-close-param-into-object.stderr +++ b/src/test/ui/regions/regions-close-param-into-object.stderr @@ -5,13 +5,7 @@ LL | fn p1(v: T) -> Box | - help: consider adding an explicit lifetime bound...: `T: 'static` ... LL | Box::new(v) - | ^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-close-param-into-object.rs:6:5 - | -LL | Box::new(v) - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:12:5 @@ -20,13 +14,7 @@ LL | fn p2(v: Box) -> Box | - help: consider adding an explicit lifetime bound...: `T: 'static` ... LL | Box::new(v) - | ^^^^^^^^^^^ - | -note: ...so that the type `std::boxed::Box` will meet its required lifetime bounds - --> $DIR/regions-close-param-into-object.rs:12:5 - | -LL | Box::new(v) - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ ...so that the type `std::boxed::Box` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:18:5 @@ -35,13 +23,7 @@ LL | fn p3<'a,T>(v: T) -> Box | - help: consider adding an explicit lifetime bound...: `T: 'a` ... LL | Box::new(v) - | ^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-close-param-into-object.rs:18:5 - | -LL | Box::new(v) - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:24:5 @@ -50,13 +32,7 @@ LL | fn p4<'a,T>(v: Box) -> Box | - help: consider adding an explicit lifetime bound...: `T: 'a` ... LL | Box::new(v) - | ^^^^^^^^^^^ - | -note: ...so that the type `std::boxed::Box` will meet its required lifetime bounds - --> $DIR/regions-close-param-into-object.rs:24:5 - | -LL | Box::new(v) - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ ...so that the type `std::boxed::Box` will meet its required lifetime bounds error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-enum-not-wf.stderr b/src/test/ui/regions/regions-enum-not-wf.stderr index 297fcb088d2bf..e32a36f72cd14 100644 --- a/src/test/ui/regions/regions-enum-not-wf.stderr +++ b/src/test/ui/regions/regions-enum-not-wf.stderr @@ -4,13 +4,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | enum Ref1<'a, T> { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref1Variant1(RequireOutlives<'a, T>) - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-enum-not-wf.rs:18:18 - | -LL | Ref1Variant1(RequireOutlives<'a, T>) - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:23:25 @@ -19,13 +13,7 @@ LL | enum Ref2<'a, T> { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref2Variant1, LL | Ref2Variant2(isize, RequireOutlives<'a, T>), - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-enum-not-wf.rs:23:25 - | -LL | Ref2Variant2(isize, RequireOutlives<'a, T>), - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:35:1 @@ -37,16 +25,7 @@ LL | enum RefDouble<'a, 'b, T> { LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) LL | | LL | | } - | |_^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-enum-not-wf.rs:35:1 - | -LL | / enum RefDouble<'a, 'b, T> { -LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) -LL | | -LL | | } - | |_^ + | |_^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:36:23 @@ -54,13 +33,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | enum RefDouble<'a, 'b, T> { | - help: consider adding an explicit lifetime bound...: `T: 'b` LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-enum-not-wf.rs:36:23 - | -LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr index 2f1a4cea8e9ac..ea59ea11a143c 100644 --- a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr @@ -5,13 +5,7 @@ LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo) | -- help: consider adding an explicit lifetime bound...: `T: 'x +` LL | { LL | wf::<&'x T>(); - | ^^^^^ - | -note: ...so that the reference type `&'x T` does not outlive the data it points at - --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:10 - | -LL | wf::<&'x T>(); - | ^^^^^ + | ^^^^^ ...so that the reference type `&'x T` does not outlive the data it points at error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr b/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr index bcdadd7a73d6c..4ca5ac291d5be 100644 --- a/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr +++ b/src/test/ui/regions/regions-infer-bound-from-trait-self.stderr @@ -5,11 +5,7 @@ LL | check_bound(x, self) | ^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `Self: 'a`... -note: ...so that the type `Self` will meet its required lifetime bounds - --> $DIR/regions-infer-bound-from-trait-self.rs:46:9 - | -LL | check_bound(x, self) - | ^^^^^^^^^^^ + = note: ...so that the type `Self` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.stderr index a5a0ff52fac12..196ee8ca7c0b5 100644 --- a/src/test/ui/regions/regions-infer-bound-from-trait.stderr +++ b/src/test/ui/regions/regions-infer-bound-from-trait.stderr @@ -4,13 +4,7 @@ error[E0309]: the parameter type `A` may not live long enough LL | fn bar1<'a,A>(x: Inv<'a>, a: A) { | - help: consider adding an explicit lifetime bound...: `A: 'a` LL | check_bound(x, a) - | ^^^^^^^^^^^ - | -note: ...so that the type `A` will meet its required lifetime bounds - --> $DIR/regions-infer-bound-from-trait.rs:33:5 - | -LL | check_bound(x, a) - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-infer-bound-from-trait.rs:37:5 @@ -18,13 +12,7 @@ error[E0309]: the parameter type `A` may not live long enough LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) { | -- help: consider adding an explicit lifetime bound...: `A: 'a +` LL | check_bound(x, a) - | ^^^^^^^^^^^ - | -note: ...so that the type `A` will meet its required lifetime bounds - --> $DIR/regions-infer-bound-from-trait.rs:37:5 - | -LL | check_bound(x, a) - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr index c3cfc5a4d97c8..2bb51731583a6 100644 --- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr @@ -4,13 +4,7 @@ error[E0310]: the parameter type `U` may not live long enough LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar - | ^^^^^^^^^^^ - | -note: ...so that the type `U` will meet its required lifetime bounds - --> $DIR/dont-infer-static.rs:8:5 - | -LL | bar: Bar - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr index 297fcb088d2bf..e32a36f72cd14 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -4,13 +4,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | enum Ref1<'a, T> { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref1Variant1(RequireOutlives<'a, T>) - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-enum-not-wf.rs:18:18 - | -LL | Ref1Variant1(RequireOutlives<'a, T>) - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:23:25 @@ -19,13 +13,7 @@ LL | enum Ref2<'a, T> { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref2Variant1, LL | Ref2Variant2(isize, RequireOutlives<'a, T>), - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-enum-not-wf.rs:23:25 - | -LL | Ref2Variant2(isize, RequireOutlives<'a, T>), - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:35:1 @@ -37,16 +25,7 @@ LL | enum RefDouble<'a, 'b, T> { LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) LL | | LL | | } - | |_^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-enum-not-wf.rs:35:1 - | -LL | / enum RefDouble<'a, 'b, T> { -LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) -LL | | -LL | | } - | |_^ + | |_^ ...so that the type `T` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:36:23 @@ -54,13 +33,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | enum RefDouble<'a, 'b, T> { | - help: consider adding an explicit lifetime bound...: `T: 'b` LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-enum-not-wf.rs:36:23 - | -LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr index f6658891fa622..44812a51778a7 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr @@ -4,13 +4,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | impl<'a, T> Trait<'a, T> for usize { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a T; - | ^^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'a T` does not outlive the data it points at - --> $DIR/regions-struct-not-wf.rs:13:5 - | -LL | type Out = &'a T; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-struct-not-wf.rs:21:5 @@ -18,13 +12,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | impl<'a, T> Trait<'a, T> for u32 { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = RefOk<'a, T>; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/regions-struct-not-wf.rs:21:5 - | -LL | type Out = RefOk<'a, T>; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references --> $DIR/regions-struct-not-wf.rs:25:5 diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index d6d2a0c4d2b63..0bd335e58e52e 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -99,15 +99,9 @@ error[E0309]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:69:44 | LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | - ^^^^^^^^^^^^^^^^^^ + | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:74:5: 76:6 g:G, dest:&mut T]` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `G: 'a` - | -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:74:5: 76:6 g:G, dest:&mut T]` will meet its required lifetime bounds - --> $DIR/missing-lifetimes-in-signature.rs:69:44 - | -LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | ^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr index b6e6c0bbf32df..643dac2572497 100644 --- a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr +++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr @@ -5,13 +5,7 @@ LL | fn foo(d: impl Debug) { | ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static` LL | LL | bar(d); - | ^^^ - | -note: ...so that the type `impl Debug` will meet its required lifetime bounds - --> $DIR/suggest-impl-trait-lifetime.rs:7:5 - | -LL | bar(d); - | ^^^ + | ^^^ ...so that the type `impl Debug` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index 22e2391f8380b..e2540e424cb19 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -22,16 +22,10 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/generic_type_does_not_live_long_enough.rs:9:1 | LL | type WrongGeneric = impl 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds ... LL | fn wrong_generic(t: T) -> WrongGeneric { | - help: consider adding an explicit lifetime bound...: `T: 'static` - | -note: ...so that the type `T` will meet its required lifetime bounds - --> $DIR/generic_type_does_not_live_long_enough.rs:9:1 - | -LL | type WrongGeneric = impl 'static; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/wf/wf-impl-associated-type-region.stderr b/src/test/ui/wf/wf-impl-associated-type-region.stderr index 9942c80effe4b..f3b32ad3f7e85 100644 --- a/src/test/ui/wf/wf-impl-associated-type-region.stderr +++ b/src/test/ui/wf/wf-impl-associated-type-region.stderr @@ -4,13 +4,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | impl<'a, T> Foo<'a> for T { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Bar = &'a T; - | ^^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'a T` does not outlive the data it points at - --> $DIR/wf-impl-associated-type-region.rs:10:5 - | -LL | type Bar = &'a T; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-static.stderr b/src/test/ui/wf/wf-in-fn-type-static.stderr index 7dc8f5a96611b..a79c446247794 100644 --- a/src/test/ui/wf/wf-in-fn-type-static.stderr +++ b/src/test/ui/wf/wf-in-fn-type-static.stderr @@ -5,13 +5,7 @@ LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: 'static LL | x: fn() -> &'static T - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'static T` does not outlive the data it points at - --> $DIR/wf-in-fn-type-static.rs:13:5 - | -LL | x: fn() -> &'static T - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error[E0310]: the parameter type `T` may not live long enough --> $DIR/wf-in-fn-type-static.rs:18:5 @@ -20,13 +14,7 @@ LL | struct Bar { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: Copy LL | x: fn(&'static T) - | ^^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'static T` does not outlive the data it points at - --> $DIR/wf-in-fn-type-static.rs:18:5 - | -LL | x: fn(&'static T) - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-in-obj-type-static.stderr b/src/test/ui/wf/wf-in-obj-type-static.stderr index 32c3198d55be4..c0057f3c82977 100644 --- a/src/test/ui/wf/wf-in-obj-type-static.stderr +++ b/src/test/ui/wf/wf-in-obj-type-static.stderr @@ -5,13 +5,7 @@ LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: 'static LL | x: dyn Object<&'static T> - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'static T` does not outlive the data it points at - --> $DIR/wf-in-obj-type-static.rs:14:5 - | -LL | x: dyn Object<&'static T> - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error: aborting due to previous error diff --git a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr index 52786fb3bca96..4c25ab9593958 100644 --- a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr +++ b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr @@ -4,13 +4,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | impl<'a, T> Trait<'a, T> for usize { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a fn(T); - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'a fn(T)` does not outlive the data it points at - --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:9:5 - | -LL | type Out = &'a fn(T); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'a fn(T)` does not outlive the data it points at error[E0309]: the parameter type `T` may not live long enough --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:19:5 @@ -18,13 +12,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | impl<'a, T> Trait<'a, T> for u32 { | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a dyn Baz; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...so that the reference type `&'a (dyn Baz + 'a)` does not outlive the data it points at - --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:19:5 - | -LL | type Out = &'a dyn Baz; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'a (dyn Baz + 'a)` does not outlive the data it points at error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-trait-associated-type-region.stderr b/src/test/ui/wf/wf-trait-associated-type-region.stderr index 9bbfad90cdb85..ae681ba6c9bb5 100644 --- a/src/test/ui/wf/wf-trait-associated-type-region.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-region.stderr @@ -5,11 +5,7 @@ LL | type Type2 = &'a Self::Type1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `>::Type1: 'a`... -note: ...so that the reference type `&'a >::Type1` does not outlive the data it points at - --> $DIR/wf-trait-associated-type-region.rs:9:5 - | -LL | type Type2 = &'a Self::Type1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...so that the reference type `&'a >::Type1` does not outlive the data it points at error: aborting due to previous error From 224ad326ea4c9d32309fbd46592661a464360b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 27 May 2020 15:33:23 -0700 Subject: [PATCH 476/695] Account for enclosing item when suggesting new lifetime name --- .../infer/error_reporting/mod.rs | 40 ++++++++++++++----- .../nice_region_error/different_lifetimes.rs | 6 +-- .../missing-lifetimes-in-signature.nll.stderr | 29 +++++++++++--- .../missing-lifetimes-in-signature.rs | 10 +++++ .../missing-lifetimes-in-signature.stderr | 34 ++++++++++++++-- 5 files changed, 96 insertions(+), 23 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index d00c90d06e4c1..c2dd3812fcc2d 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -60,7 +60,7 @@ use rustc_errors::{pluralize, struct_span_err}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::Node; +use rustc_hir::{Item, ItemKind, Node}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, @@ -1685,12 +1685,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let hir = &self.tcx.hir(); // Attempt to obtain the span of the parameter so we can // suggest adding an explicit lifetime bound to it. - let generics = self - .in_progress_tables - .and_then(|table| table.borrow().hir_owner) - .map(|table_owner| self.tcx.generics_of(table_owner.to_def_id())); + let generics = + self.in_progress_tables.and_then(|table| table.borrow().hir_owner).map(|table_owner| { + let hir_id = hir.as_local_hir_id(table_owner); + let parent_id = hir.get_parent_item(hir_id); + ( + // Parent item could be a `mod`, so we check the HIR before calling: + if let Some(Node::Item(Item { + kind: ItemKind::Trait(..) | ItemKind::Impl { .. }, + .. + })) = hir.find(parent_id) + { + Some(self.tcx.generics_of(hir.local_def_id(parent_id).to_def_id())) + } else { + None + }, + self.tcx.generics_of(table_owner.to_def_id()), + ) + }); let type_param_span = match (generics, bound_kind) { - (Some(ref generics), GenericKind::Param(ref param)) => { + (Some((_, ref generics)), GenericKind::Param(ref param)) => { // Account for the case where `param` corresponds to `Self`, // which doesn't have the expected type argument. if !(generics.has_self && param.index == 0) { @@ -1727,21 +1741,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let new_lt = generics .as_ref() - .and_then(|g| { + .and_then(|(parent_g, g)| { let possible = ["'a", "'b", "'c", "'d", "'e", "'f", "'g", "'h", "'i", "'j", "'k"]; - let lts_names = g + let mut lts_names = g .params .iter() .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) .map(|p| p.name.as_str()) .collect::>(); + if let Some(g) = parent_g { + lts_names.extend( + g.params + .iter() + .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) + .map(|p| p.name.as_str()), + ); + } let lts = lts_names.iter().map(|s| -> &str { &*s }).collect::>(); possible.iter().filter(|&candidate| !lts.contains(&*candidate)).next().map(|s| *s) }) .unwrap_or("'lt"); let add_lt_sugg = generics .as_ref() - .and_then(|g| g.params.first()) + .and_then(|(_, g)| g.params.first()) .and_then(|param| param.def_id.as_local()) .map(|def_id| { (hir.span(hir.as_local_hir_id(def_id)).shrink_to_lo(), format!("{}, ", new_lt)) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs index d206a30d526cb..7ab18e54f7ea2 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -121,16 +121,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { (Some(ret_span), _) => ( ty_sub.span, ret_span, - "this parameter and the return type are declared \ - with different lifetimes..." + "this parameter and the return type are declared with different lifetimes..." .to_owned(), format!("...but data{} is returned here", span_label_var1), ), (_, Some(ret_span)) => ( ty_sup.span, ret_span, - "this parameter and the return type are declared \ - with different lifetimes..." + "this parameter and the return type are declared with different lifetimes..." .to_owned(), format!("...but data{} is returned here", span_label_var1), ), diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr index f11c978aabf58..2072b00f7b2cb 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr @@ -56,13 +56,30 @@ LL | | } | |_^ error[E0311]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:58:45 + --> $DIR/missing-lifetimes-in-signature.rs:59:58 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the method body at 59:5... + --> $DIR/missing-lifetimes-in-signature.rs:59:5 + | +LL | / fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_____^ + +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:68:45 | LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | ^^^^^^^^^^^^^^^^^^^^^^^ | -note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 58:1... - --> $DIR/missing-lifetimes-in-signature.rs:58:1 +note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the function body at 68:1... + --> $DIR/missing-lifetimes-in-signature.rs:68:1 | LL | / fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a LL | | @@ -74,7 +91,7 @@ LL | | } | |_^ error[E0621]: explicit lifetime required in the type of `dest` - --> $DIR/missing-lifetimes-in-signature.rs:63:5 + --> $DIR/missing-lifetimes-in-signature.rs:73:5 | LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` @@ -85,14 +102,14 @@ LL | | } | |_____^ lifetime `'a` required error[E0309]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:69:44 + --> $DIR/missing-lifetimes-in-signature.rs:79:44 | LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a | ^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `G: 'a`... -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors Some errors have detailed explanations: E0261, E0309, E0621. For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs index 589d04c9b1962..d3853445dfdfe 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs @@ -54,6 +54,16 @@ where } } +// Same as above, but show that we pay attention to lifetime names from parent item +impl<'a> Foo { + fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + //~^ ERROR the parameter type `G` may not live long enough + move || { + *dest = g.get(); + } + } +} + // After applying suggestion for `qux`: fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a //~^ ERROR explicit lifetime required in the type of `dest` diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 0bd335e58e52e..46fd0e1052ecd 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -87,8 +87,34 @@ help: consider introducing an explicit lifetime bound LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b | ^^^ ^^^^^^^ ^^^^ +error[E0311]: the parameter type `G` may not live long enough + --> $DIR/missing-lifetimes-in-signature.rs:59:58 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `G` must be valid for the anonymous lifetime #1 defined on the method body at 59:5... + --> $DIR/missing-lifetimes-in-signature.rs:59:5 + | +LL | / fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { +LL | | +LL | | move || { +LL | | *dest = g.get(); +LL | | } +LL | | } + | |_____^ +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10 g:G, dest:&mut T]` will meet its required lifetime bounds + --> $DIR/missing-lifetimes-in-signature.rs:59:58 + | +LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ^^^^^^^^^^^^^^^^^^ +help: consider introducing an explicit lifetime bound + | +LL | fn qux<'c, 'b, G: 'c + Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c { + | ^^^ ^^^^^^^ ^^^^ + error[E0621]: explicit lifetime required in the type of `dest` - --> $DIR/missing-lifetimes-in-signature.rs:58:45 + --> $DIR/missing-lifetimes-in-signature.rs:68:45 | LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | ------ ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required @@ -96,14 +122,14 @@ LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a | help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` error[E0309]: the parameter type `G` may not live long enough - --> $DIR/missing-lifetimes-in-signature.rs:69:44 + --> $DIR/missing-lifetimes-in-signature.rs:79:44 | LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:74:5: 76:6 g:G, dest:&mut T]` will meet its required lifetime bounds + | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6 g:G, dest:&mut T]` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `G: 'a` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0261, E0309, E0621. For more information about an error, try `rustc --explain E0261`. From 6dcd744df0ed404b58767e17f55e1b4f1351daa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 27 May 2020 15:44:42 -0700 Subject: [PATCH 477/695] Consider all possible one letter lifetimes in suggestion --- src/librustc_infer/infer/error_reporting/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index c2dd3812fcc2d..a59a91e3005aa 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -1742,7 +1742,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let new_lt = generics .as_ref() .and_then(|(parent_g, g)| { - let possible = ["'a", "'b", "'c", "'d", "'e", "'f", "'g", "'h", "'i", "'j", "'k"]; + let possible: Vec<_> = (b'a'..=b'z').map(|c| format!("'{}", c as char)).collect(); let mut lts_names = g .params .iter() @@ -1758,9 +1758,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); } let lts = lts_names.iter().map(|s| -> &str { &*s }).collect::>(); - possible.iter().filter(|&candidate| !lts.contains(&*candidate)).next().map(|s| *s) + possible.into_iter().find(|candidate| !lts.contains(&candidate.as_str())) }) - .unwrap_or("'lt"); + .unwrap_or("'lt".to_string()); let add_lt_sugg = generics .as_ref() .and_then(|(_, g)| g.params.first()) From 83f6f2235892853c152d08551975525b7ae79914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 May 2020 11:54:40 -0700 Subject: [PATCH 478/695] Tweak wording and spans of `'static` `dyn Trait`/`impl Trait` requirements --- .../nice_region_error/static_impl_trait.rs | 47 ++++++++++--------- .../ui/async-await/issues/issue-62097.stderr | 13 ++--- .../must_outlive_least_region_or_bound.stderr | 42 ++++++----------- .../static-return-lifetime-infered.stderr | 28 ++++------- src/test/ui/issues/issue-16922.stderr | 16 ++----- ...ect-lifetime-default-from-box-error.stderr | 17 ++----- .../region-object-lifetime-in-coercion.stderr | 18 +++---- ...types_pin_lifetime_impl_trait-async.stderr | 13 ++--- ..._self_types_pin_lifetime_impl_trait.stderr | 14 ++---- .../missing-lifetimes-in-signature.stderr | 19 ++------ .../dyn-trait-underscore.stderr | 20 ++------ 11 files changed, 91 insertions(+), 156 deletions(-) diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index 5c5c86a4fb118..f4c86ddae604e 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -27,28 +27,32 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let return_sp = sub_origin.span(); let mut err = self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime"); - if sp == sup_origin.span() && return_sp == sp { - // Example: `ui/object-lifetime/object-lifetime-default-from-box-error.rs` - err.span_label( - sup_origin.span(), - "this needs to be `'static` but the borrow...", - ); - } else { - err.span_label(return_sp, "this is `'static`..."); - // We try to make the output have fewer overlapping spans if possible. - if sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()) { - // When `sp == sup_origin` we already have overlapping spans in the - // main diagnostic output, so we don't split this into its own note. - err.span_label(sup_origin.span(), "...but this borrow..."); + let param_info = self.find_param_with_region(sup_r, sub_r)?; + err.span_label(param_info.param_ty_span, "data with this lifetime..."); + + // We try to make the output have fewer overlapping spans if possible. + if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) + && sup_origin.span() != return_sp + { + // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` + + // Customize the spans and labels depending on their relative order so + // that split sentences flow correctly. + if sup_origin.span().shrink_to_hi() <= return_sp.shrink_to_lo() { + err.span_label(sup_origin.span(), "...is captured here..."); + err.span_label(return_sp, "...and required to be `'static` by this"); } else { - err.span_note(sup_origin.span(), "...but this borrow..."); + err.span_label(return_sp, "...is required to be `'static` by this..."); + err.span_label(sup_origin.span(), "...and is captured here"); } + } else { + err.span_label( + return_sp, + "...is captured and required to be `'static` here", + ); } - let (lifetime, lt_sp_opt) = msg_span_from_free_region(self.tcx(), sup_r); - if let Some(lifetime_sp) = lt_sp_opt { - err.span_note(lifetime_sp, &format!("...can't outlive {}", lifetime)); - } + let (lifetime, _) = msg_span_from_free_region(self.tcx(), sup_r); let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; @@ -56,10 +60,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // explicit non-desugar'able return. if fn_return_span.desugaring_kind().is_none() { let msg = format!( - "you can add a bound to the returned `{} Trait` to make it last less \ - than `'static` and match {}", + "to permit non-static references in {} `{} Trait` value, you can add \ + an explicit bound for {}", + if is_dyn { "a" } else { "an" }, if is_dyn { "dyn" } else { "impl" }, - lifetime + lifetime, ); // FIXME: account for the need of parens in `&(dyn Trait + '_)` err.span_suggestion_verbose( diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 161b2565c3dfc..af8fc2cd2ab45 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -2,15 +2,12 @@ error: cannot infer an appropriate lifetime --> $DIR/issue-62097.rs:12:31 | LL | pub async fn run_dummy_fn(&self) { - | ^^^^^ ...but this borrow... + | ^^^^^ + | | + | data with this lifetime... + | ...is captured here... LL | foo(|| self.bar()).await; - | --- this is `'static`... - | -note: ...can't outlive the lifetime `'_` as defined on the method body at 12:31 - --> $DIR/issue-62097.rs:12:31 - | -LL | pub async fn run_dummy_fn(&self) { - | ^ + | --- ...and required to be `'static` by this error: aborting due to previous error diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 0079fabb58d33..d7dae6a08a7b9 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -2,16 +2,12 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } - | --------- ^ ...but this borrow... - | | - | this is `'static`... + | ---- --------- ^ ...and is captured here + | | | + | | ...is required to be `'static` by this... + | data with this lifetime... | -note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1 - --> $DIR/must_outlive_least_region_or_bound.rs:3:1 - | -LL | fn elided(x: &i32) -> impl Copy { x } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1 | LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^ @@ -20,16 +16,12 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:6:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } - | --------- ^ ...but this borrow... - | | - | this is `'static`... - | -note: ...can't outlive the lifetime `'a` as defined on the function body at 6:13 - --> $DIR/must_outlive_least_region_or_bound.rs:6:13 + | ------- --------- ^ ...and is captured here + | | | + | | ...is required to be `'static` by this... + | data with this lifetime... | -LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } - | ^^ -help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 6:13 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 6:13 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ @@ -38,16 +30,12 @@ error: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:12:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } - | -------------------------------- ^ ...but this borrow... - | | - | this is `'static`... - | -note: ...can't outlive the lifetime `'a` as defined on the function body at 12:15 - --> $DIR/must_outlive_least_region_or_bound.rs:12:15 + | ------- -------------------------------- ^ ...and is captured here + | | | + | | ...is required to be `'static` by this... + | data with this lifetime... | -LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } - | ^^ -help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the lifetime `'a` as defined on the function body at 12:15 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:15 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x } | ^^^^ diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index 645c7e1e1954c..1c3a5979ee55b 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -2,20 +2,15 @@ error: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator { - | ----------------------- this is `'static`... + | ----- ----------------------- ...is required to be `'static` by this... + | | + | data with this lifetime... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | - | ...but this borrow... + | ...and is captured here | -note: ...can't outlive the anonymous lifetime #1 defined on the method body at 6:5 - --> $DIR/static-return-lifetime-infered.rs:6:5 - | -LL | / fn iter_values_anon(&self) -> impl Iterator { -LL | | self.x.iter().map(|a| a.0) -LL | | } - | |_____^ -help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 6:5 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5 | LL | fn iter_values_anon(&self) -> impl Iterator + '_ { | ^^^^ @@ -24,18 +19,15 @@ error: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:11:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator { - | ----------------------- this is `'static`... + | -------- ----------------------- ...is required to be `'static` by this... + | | + | data with this lifetime... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | - | ...but this borrow... - | -note: ...can't outlive the lifetime `'a` as defined on the method body at 10:20 - --> $DIR/static-return-lifetime-infered.rs:10:20 + | ...and is captured here | -LL | fn iter_values<'a>(&'a self) -> impl Iterator { - | ^^ -help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the lifetime `'a` as defined on the method body at 10:20 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the method body at 10:20 | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { | ^^^^ diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 20a6b287429f9..02d33aae023ff 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -1,21 +1,15 @@ error: cannot infer an appropriate lifetime --> $DIR/issue-16922.rs:4:14 | +LL | fn foo(value: &T) -> Box { + | -- data with this lifetime... LL | Box::new(value) as Box | ---------^^^^^- | | | - | | ...but this borrow... - | this is `'static`... + | | ...and is captured here + | ...is required to be `'static` by this... | -note: ...can't outlive the anonymous lifetime #1 defined on the function body at 3:1 - --> $DIR/issue-16922.rs:3:1 - | -LL | / fn foo(value: &T) -> Box { -LL | | Box::new(value) as Box -LL | | -LL | | } - | |_^ -help: you can add a bound to the returned `dyn Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 3:1 +help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1 | LL | fn foo(value: &T) -> Box { | ^^^^ diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 465409c639891..70a9bf22b8db3 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -1,20 +1,13 @@ error: cannot infer an appropriate lifetime --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | +LL | fn load(ss: &mut SomeStruct) -> Box { + | --------------- data with this lifetime... +... LL | ss.r - | ^^^^ this needs to be `'static` but the borrow... - | -note: ...can't outlive the anonymous lifetime #2 defined on the function body at 14:1 - --> $DIR/object-lifetime-default-from-box-error.rs:14:1 + | ^^^^ ...is captured and required to be `'static` here | -LL | / fn load(ss: &mut SomeStruct) -> Box { -LL | | // `Box` defaults to a `'static` bound, so this return -LL | | // is illegal. -LL | | -LL | | ss.r -LL | | } - | |_^ -help: you can add a bound to the returned `dyn Trait` to make it last less than `'static` and match the anonymous lifetime #2 defined on the function body at 14:1 +help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1 | LL | fn load(ss: &mut SomeStruct) -> Box { | ^^^^ diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 5a414c477a69f..1462af44cb15a 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -17,22 +17,16 @@ LL | Box::new(v) error: cannot infer an appropriate lifetime --> $DIR/region-object-lifetime-in-coercion.rs:20:14 | +LL | fn c(v: &[u8]) -> Box { + | ----- data with this lifetime... +... LL | Box::new(v) | ---------^- | | | - | | ...but this borrow... - | this is `'static`... + | | ...and is captured here + | ...is required to be `'static` by this... | -note: ...can't outlive the anonymous lifetime #1 defined on the function body at 17:1 - --> $DIR/region-object-lifetime-in-coercion.rs:17:1 - | -LL | / fn c(v: &[u8]) -> Box { -LL | | // same as previous case due to RFC 599 -LL | | -LL | | Box::new(v) -LL | | } - | |_^ -help: you can add a bound to the returned `dyn Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 17:1 +help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 17:1 | LL | fn c(v: &[u8]) -> Box { | ^^^^ diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 21775539cea76..1aeabce5e8aaf 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -2,15 +2,10 @@ error: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^ ---------- this is `'static`... - | | - | ...but this borrow... - | -note: ...can't outlive the lifetime `'_` as defined on the method body at 8:26 - --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:26 - | -LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^ + | ^^^^ ---------- ---------- ...and required to be `'static` by this + | | | + | | data with this lifetime... + | ...is captured here... error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index e931cec8a2a84..04c475be787b8 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -2,16 +2,12 @@ error: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } - | ---------- ^^^^ ...but this borrow... - | | - | this is `'static`... + | ---------- ---------- ^^^^ ...and is captured here + | | | + | | ...is required to be `'static` by this... + | data with this lifetime... | -note: ...can't outlive the anonymous lifetime #1 defined on the method body at 6:5 - --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:5 - | -LL | fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 6:5 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5 | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } | ^^^^ diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 46fd0e1052ecd..5cf170d566ca9 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -10,25 +10,16 @@ error: cannot infer an appropriate lifetime --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() - | ------------- this is `'static`... + | ------ ------------- ...is required to be `'static` by this... + | | + | data with this lifetime... ... LL | / move || { LL | | *dest = g.get(); LL | | } - | |_____^ ...but this borrow... + | |_____^ ...and is captured here | -note: ...can't outlive the anonymous lifetime #1 defined on the function body at 15:1 - --> $DIR/missing-lifetimes-in-signature.rs:15:1 - | -LL | / fn foo(g: G, dest: &mut T) -> impl FnOnce() -LL | | where -LL | | G: Get -LL | | { -... | -LL | | } -LL | | } - | |_^ -help: you can add a bound to the returned `impl Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 15:1 +help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 15:1 | LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index bcbdec4f306d9..3577dd59289e5 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,23 +1,13 @@ error: cannot infer an appropriate lifetime --> $DIR/dyn-trait-underscore.rs:8:20 | +LL | fn a(items: &[T]) -> Box> { + | ---- data with this lifetime... +LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ---------------^^^^--- this is `'static`... + | ---------------^^^^--- ...is captured and required to be `'static` here | -note: ...but this borrow... - --> $DIR/dyn-trait-underscore.rs:8:14 - | -LL | Box::new(items.iter()) - | ^^^^^ -note: ...can't outlive the anonymous lifetime #1 defined on the function body at 6:1 - --> $DIR/dyn-trait-underscore.rs:6:1 - | -LL | / fn a(items: &[T]) -> Box> { -LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` -LL | | Box::new(items.iter()) -LL | | } - | |_^ -help: you can add a bound to the returned `dyn Trait` to make it last less than `'static` and match the anonymous lifetime #1 defined on the function body at 6:1 +help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1 | LL | fn a(items: &[T]) -> Box + '_> { | ^^^^ From 4d5ce340cd643cbb775728cfd223a7a4b5281bae Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 31 May 2020 00:04:57 +0300 Subject: [PATCH 479/695] test-macros: Avoid always producing errors in `#[derive(Print)]` --- .../ui/proc-macro/auxiliary/test-macros.rs | 3 +- src/test/ui/proc-macro/dollar-crate.rs | 5 ++-- src/test/ui/proc-macro/dollar-crate.stderr | 30 ------------------- 3 files changed, 5 insertions(+), 33 deletions(-) delete mode 100644 src/test/ui/proc-macro/dollar-crate.stderr diff --git a/src/test/ui/proc-macro/auxiliary/test-macros.rs b/src/test/ui/proc-macro/auxiliary/test-macros.rs index 27efa44f98032..fb8016cd43896 100644 --- a/src/test/ui/proc-macro/auxiliary/test-macros.rs +++ b/src/test/ui/proc-macro/auxiliary/test-macros.rs @@ -108,5 +108,6 @@ pub fn print_attr(_: TokenStream, input: TokenStream) -> TokenStream { #[proc_macro_derive(Print, attributes(print_helper))] pub fn print_derive(input: TokenStream) -> TokenStream { - print_helper(input, "DERIVE") + print_helper(input, "DERIVE"); + TokenStream::new() } diff --git a/src/test/ui/proc-macro/dollar-crate.rs b/src/test/ui/proc-macro/dollar-crate.rs index aadd87ffaf203..5f2549376d1ba 100644 --- a/src/test/ui/proc-macro/dollar-crate.rs +++ b/src/test/ui/proc-macro/dollar-crate.rs @@ -1,3 +1,4 @@ +// check-pass // edition:2018 // aux-build:test-macros.rs // aux-build:dollar-crate-external.rs @@ -23,7 +24,7 @@ mod local { struct A($crate::S); #[derive(Print)] - struct D($crate::S); //~ ERROR the name `D` is defined multiple times + struct D($crate::S); }; } @@ -33,7 +34,7 @@ mod local { mod external { use crate::dollar_crate_external; - dollar_crate_external::external!(); //~ ERROR the name `D` is defined multiple times + dollar_crate_external::external!(); } fn main() {} diff --git a/src/test/ui/proc-macro/dollar-crate.stderr b/src/test/ui/proc-macro/dollar-crate.stderr deleted file mode 100644 index 465f242580dfb..0000000000000 --- a/src/test/ui/proc-macro/dollar-crate.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0428]: the name `D` is defined multiple times - --> $DIR/dollar-crate.rs:26:13 - | -LL | struct D($crate::S); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | `D` redefined here - | previous definition of the type `D` here -... -LL | local!(); - | --------- in this macro invocation - | - = note: `D` must be defined only once in the type namespace of this module - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0428]: the name `D` is defined multiple times - --> $DIR/dollar-crate.rs:36:5 - | -LL | dollar_crate_external::external!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `D` redefined here - | previous definition of the type `D` here - | - = note: `D` must be defined only once in the type namespace of this module - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0428`. From 81e06dac84fe073016befc2e860310fcd87715d6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 31 May 2020 00:20:06 +0300 Subject: [PATCH 480/695] Add a test for `$:ident` in proc macro input --- src/test/ui/proc-macro/input-interpolated.rs | 25 +++++++ .../ui/proc-macro/input-interpolated.stdout | 69 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/test/ui/proc-macro/input-interpolated.rs create mode 100644 src/test/ui/proc-macro/input-interpolated.stdout diff --git a/src/test/ui/proc-macro/input-interpolated.rs b/src/test/ui/proc-macro/input-interpolated.rs new file mode 100644 index 0000000000000..b57ce99b13841 --- /dev/null +++ b/src/test/ui/proc-macro/input-interpolated.rs @@ -0,0 +1,25 @@ +// Check what token streams proc macros see when interpolated tokens are passed to them as input. + +// check-pass +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +macro_rules! pass_ident { + ($i:ident) => { + fn f() { + print_bang!($i); + } + + #[print_attr] + const $i: u8 = 0; + + #[derive(Print)] + struct $i {} + }; +} + +pass_ident!(A); + +fn main() {} diff --git a/src/test/ui/proc-macro/input-interpolated.stdout b/src/test/ui/proc-macro/input-interpolated.stdout new file mode 100644 index 0000000000000..7529db3bd06f8 --- /dev/null +++ b/src/test/ui/proc-macro/input-interpolated.stdout @@ -0,0 +1,69 @@ +PRINT-BANG INPUT (DISPLAY): A +PRINT-BANG RE-COLLECTED (DISPLAY): A +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "A", + span: #0 bytes(402..403), + }, + ], + span: #3 bytes(269..271), + }, +] +PRINT-ATTR INPUT (DISPLAY): const A: u8 = 0; +PRINT-ATTR RE-COLLECTED (DISPLAY): const A : u8 = 0 ; +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "const", + span: #0 bytes(0..0), + }, + Ident { + ident: "A", + span: #0 bytes(0..0), + }, + Punct { + ch: ':', + spacing: Alone, + span: #0 bytes(0..0), + }, + Ident { + ident: "u8", + span: #0 bytes(0..0), + }, + Punct { + ch: '=', + spacing: Alone, + span: #0 bytes(0..0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: #0 bytes(0..0), + }, + Punct { + ch: ';', + spacing: Alone, + span: #0 bytes(0..0), + }, +] +PRINT-DERIVE INPUT (DISPLAY): struct A { +} +PRINT-DERIVE RE-COLLECTED (DISPLAY): struct A { } +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Ident { + ident: "struct", + span: #0 bytes(0..0), + }, + Ident { + ident: "A", + span: #0 bytes(0..0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: #0 bytes(0..0), + }, +] From 15201af7edbf93732756510527977327563b44e8 Mon Sep 17 00:00:00 2001 From: Mahmut Bulut Date: Fri, 29 May 2020 20:28:18 +0200 Subject: [PATCH 481/695] Update stdarch submodule to latest head --- src/stdarch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stdarch b/src/stdarch index ec6fccd34c300..45340c0e2fdad 160000 --- a/src/stdarch +++ b/src/stdarch @@ -1 +1 @@ -Subproject commit ec6fccd34c30003a7ebf4e7a9dfe4e31f5b76e1b +Subproject commit 45340c0e2fdadf2f131ef43cb683b5cafab0ff15 From 3bf9eb0f7a1f2da9df2983aa8cf95a420130cada Mon Sep 17 00:00:00 2001 From: XIAO Tian Date: Sat, 30 May 2020 11:28:33 +0800 Subject: [PATCH 482/695] Add a test for wrong assoc type diagnostics --- src/test/ui/associated-types/issue-72806.rs | 20 +++++++++++++++++++ .../ui/associated-types/issue-72806.stderr | 9 +++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/test/ui/associated-types/issue-72806.rs create mode 100644 src/test/ui/associated-types/issue-72806.stderr diff --git a/src/test/ui/associated-types/issue-72806.rs b/src/test/ui/associated-types/issue-72806.rs new file mode 100644 index 0000000000000..ae63781d568a1 --- /dev/null +++ b/src/test/ui/associated-types/issue-72806.rs @@ -0,0 +1,20 @@ +trait Bar { + type Ok; + type Sibling: Bar2; +} +trait Bar2 { + type Ok; +} + +struct Foo; +struct Foo2; + +impl Bar for Foo { //~ ERROR type mismatch resolving `::Ok == char` + type Ok = (); + type Sibling = Foo2; +} +impl Bar2 for Foo2 { + type Ok = u32; +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-72806.stderr b/src/test/ui/associated-types/issue-72806.stderr new file mode 100644 index 0000000000000..03a6565848dc3 --- /dev/null +++ b/src/test/ui/associated-types/issue-72806.stderr @@ -0,0 +1,9 @@ +error[E0271]: type mismatch resolving `::Ok == char` + --> $DIR/issue-72806.rs:12:6 + | +LL | impl Bar for Foo { + | ^^^ expected `u32`, found `char` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. From 1a68c8e8d957e8df19e5adced776879bbe3d5344 Mon Sep 17 00:00:00 2001 From: XIAO Tian Date: Sat, 30 May 2020 11:26:46 +0800 Subject: [PATCH 483/695] Fix associate type diagnostics --- src/librustc_trait_selection/traits/wf.rs | 31 +++++++++-------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 714ca7a30cff6..39c7528a63240 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -172,25 +172,18 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( }; match pred.kind() { ty::PredicateKind::Projection(proj) => { - // The obligation comes not from the current `impl` nor the `trait` being - // implemented, but rather from a "second order" obligation, like in - // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`. - let trait_assoc_item = tcx.associated_item(proj.projection_def_id()); - if let Some(impl_item_span) = - items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) - { - cause.span = impl_item_span; - } else { - let kind = &proj.ty().skip_binder().kind; - if let ty::Projection(projection_ty) = kind { - // This happens when an associated type has a projection coming from another - // associated type. See `traits-assoc-type-in-supertrait-bad.rs`. - let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id); - if let Some(impl_item_span) = - items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) - { - cause.span = impl_item_span; - } + // The obligation comes not from the current `impl` nor the `trait` being implemented, + // but rather from a "second order" obligation, where an associated type has a + // projection coming from another associated type. See + // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and + // `traits-assoc-type-in-supertrait-bad.rs`. + let kind = &proj.ty().skip_binder().kind; + if let ty::Projection(projection_ty) = kind { + let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id); + if let Some(impl_item_span) = + items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) + { + cause.span = impl_item_span; } } } From 04417636945004b91de8e3f32ee10e80585d05ec Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 31 May 2020 09:58:28 +0200 Subject: [PATCH 484/695] remove fixme for `stalled_on` --- src/librustc_trait_selection/traits/fulfill.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 252c84fba8784..c1d9b0a2d88e6 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -75,9 +75,10 @@ pub struct FulfillmentContext<'tcx> { #[derive(Clone, Debug)] pub struct PendingPredicateObligation<'tcx> { pub obligation: PredicateObligation<'tcx>, - // FIXME(eddyb) look into whether this could be a `SmallVec`. - // Judging by the comment in `process_obligation`, the 1-element case - // is common so this could be a `SmallVec<[TyOrConstInferVar<'tcx>; 1]>`. + // This is far more often read than modified, meaning that we + // should mostly optimize for reading speed, while modifying is not as relevant. + // + // For whatever reason using a boxed slice is slower than using a `Vec` here. pub stalled_on: Vec>, } From 57078384809fffafac4e90e18cc37a91a1dd5200 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 09:52:51 +0200 Subject: [PATCH 485/695] validate basic sanity for TerminatorKind --- src/librustc_mir/interpret/terminator.rs | 8 +- src/librustc_mir/transform/validate.rs | 103 ++++++++++++++++++++++- 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index b048240ca8dc1..3db16a71bab15 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -50,7 +50,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.go_to_block(target_block); } - Call { ref func, ref args, destination, ref cleanup, .. } => { + Call { + ref func, + ref args, + destination, + ref cleanup, + from_hir_call: _from_hir_call, + } => { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index a25edd131baa1..046889193dac3 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -3,8 +3,11 @@ use super::{MirPass, MirSource}; use rustc_middle::mir::visit::Visitor; use rustc_middle::{ - mir::{Body, Location, Operand, Rvalue, Statement, StatementKind}, - ty::{ParamEnv, TyCtxt}, + mir::{ + BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator, + TerminatorKind, + }, + ty::{self, ParamEnv, TyCtxt}, }; use rustc_span::{def_id::DefId, Span, DUMMY_SP}; @@ -38,6 +41,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &format!("broken MIR in {:?} ({}): {}", self.def_id, self.when, msg.as_ref()), ); } + + fn check_bb(&self, span: Span, bb: BasicBlock) { + if self.body.basic_blocks().get(bb).is_none() { + self.fail(span, format!("encountered jump to invalid basic block {:?}", bb)) + } + } } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { @@ -77,4 +86,94 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _location: Location) { + match &terminator.kind { + TerminatorKind::Goto { target } => { + self.check_bb(terminator.source_info.span, *target); + } + TerminatorKind::SwitchInt { targets, .. } => { + if targets.is_empty() { + self.fail( + terminator.source_info.span, + "encountered `SwitchInt` terminator with no target to jump to", + ); + } + for target in targets { + self.check_bb(terminator.source_info.span, *target); + } + } + TerminatorKind::Drop { target, unwind, .. } => { + self.check_bb(terminator.source_info.span, *target); + if let Some(unwind) = unwind { + self.check_bb(terminator.source_info.span, *unwind); + } + } + TerminatorKind::DropAndReplace { target, unwind, .. } => { + self.check_bb(terminator.source_info.span, *target); + if let Some(unwind) = unwind { + self.check_bb(terminator.source_info.span, *unwind); + } + } + TerminatorKind::Call { func, destination, cleanup, .. } => { + let func_ty = func.ty(&self.body.local_decls, self.tcx); + match func_ty.kind { + ty::FnPtr(..) | ty::FnDef(..) => {} + _ => self.fail( + terminator.source_info.span, + format!("encountered non-callable type {} in `Call` terminator", func_ty), + ), + } + if let Some((_, target)) = destination { + self.check_bb(terminator.source_info.span, *target); + } + if let Some(cleanup) = cleanup { + self.check_bb(terminator.source_info.span, *cleanup); + } + } + TerminatorKind::Assert { cond, target, cleanup, .. } => { + let cond_ty = cond.ty(&self.body.local_decls, self.tcx); + if cond_ty != self.tcx.types.bool { + self.fail( + terminator.source_info.span, + format!( + "encountered non-boolean condition of type {} in `Assert` terminator", + cond_ty + ), + ); + } + self.check_bb(terminator.source_info.span, *target); + if let Some(cleanup) = cleanup { + self.check_bb(terminator.source_info.span, *cleanup); + } + } + TerminatorKind::Yield { resume, drop, .. } => { + self.check_bb(terminator.source_info.span, *resume); + if let Some(drop) = drop { + self.check_bb(terminator.source_info.span, *drop); + } + } + TerminatorKind::FalseEdges { real_target, imaginary_target } => { + self.check_bb(terminator.source_info.span, *real_target); + self.check_bb(terminator.source_info.span, *imaginary_target); + } + TerminatorKind::FalseUnwind { real_target, unwind } => { + self.check_bb(terminator.source_info.span, *real_target); + if let Some(unwind) = unwind { + self.check_bb(terminator.source_info.span, *unwind); + } + } + TerminatorKind::InlineAsm { destination, .. } => { + if let Some(destination) = destination { + self.check_bb(terminator.source_info.span, *destination); + } + } + // Nothing to validate for these. + TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop => {} + } + } } From 79449986b707c18df92622a53d83eddd6872d8ee Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 31 May 2020 17:16:47 +0800 Subject: [PATCH 486/695] Rearrange impl blocks with Deref as first The other blocks depends on Deref to make it easier for readers when reimplementing or reading the implementations. --- src/liballoc/vec.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 42fb1f8c737b3..6409c66b08140 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1900,6 +1900,22 @@ unsafe impl IsZero for Option> { // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Deref for Vec { + type Target = [T]; + + fn deref(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::DerefMut for Vec { + fn deref_mut(&mut self) -> &mut [T] { + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { #[cfg(not(test))] @@ -1955,22 +1971,6 @@ impl> IndexMut for Vec { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Deref for Vec { - type Target = [T]; - - fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::DerefMut for Vec { - fn deref_mut(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for Vec { #[inline] From 71404633e843e0e5a533c677a764c8cb7f2a55fb Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 31 May 2020 17:19:06 +0800 Subject: [PATCH 487/695] Merge raw_vec into_box with previous impl There are two separate `impl` which no special reason, it would be better to merge both of them. --- src/liballoc/raw_vec.rs | 50 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 56e284a12fa83..5b365f0387a9b 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -118,6 +118,30 @@ impl RawVec { RawVec::from_raw_parts(slice.as_mut_ptr(), slice.len()) } } + + /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. + /// + /// Note that this will correctly reconstitute any `cap` changes + /// that may have been performed. (See description of type for details.) + /// + /// # Safety + /// + /// * `len` must be greater than or equal to the most recently requested capacity, and + /// * `len` must be less than or equal to `self.capacity()`. + /// + /// Note, that the requested capacity and `self.capacity()` could differ, as + /// an allocator could overallocate and return a greater memory block than requested. + pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit]> { + // Sanity-check one half of the safety requirement (we cannot check the other half). + debug_assert!( + len <= self.capacity(), + "`len` must be smaller than or equal to `self.capacity()`" + ); + + let me = ManuallyDrop::new(self); + let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); + Box::from_raw(slice) + } } impl RawVec { @@ -520,32 +544,6 @@ where Ok(memory) } -impl RawVec { - /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. - /// - /// Note that this will correctly reconstitute any `cap` changes - /// that may have been performed. (See description of type for details.) - /// - /// # Safety - /// - /// * `len` must be greater than or equal to the most recently requested capacity, and - /// * `len` must be less than or equal to `self.capacity()`. - /// - /// Note, that the requested capacity and `self.capacity()` could differ, as - /// an allocator could overallocate and return a greater memory block than requested. - pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit]> { - // Sanity-check one half of the safety requirement (we cannot check the other half). - debug_assert!( - len <= self.capacity(), - "`len` must be smaller than or equal to `self.capacity()`" - ); - - let me = ManuallyDrop::new(self); - let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit, len); - Box::from_raw(slice) - } -} - unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { /// Frees the memory owned by the `RawVec` *without* trying to drop its contents. fn drop(&mut self) { From 532dabdb8ef9536abc68c6adcdd9ca557c0e445a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 11:58:15 +0200 Subject: [PATCH 488/695] Miri tests: skip parts of test_char_range --- src/libcore/tests/iter.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index ab4f4aa7c73c8..3b854b56c320d 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1959,8 +1959,11 @@ fn test_range() { #[test] fn test_char_range() { use std::char; - assert!(('\0'..=char::MAX).eq((0..=char::MAX as u32).filter_map(char::from_u32))); - assert!(('\0'..=char::MAX).rev().eq((0..=char::MAX as u32).filter_map(char::from_u32).rev())); + // Miri is too slow + let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' }; + let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX }; + assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32))); + assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev())); assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2); assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2))); From 37381d33a4761a064311dd95fbc54b5da6ad3766 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 31 May 2020 14:05:57 +0200 Subject: [PATCH 489/695] Fix sync fallout --- clippy_lints/src/needless_pass_by_value.rs | 8 +------- clippy_lints/src/write.rs | 13 ++++++------- tests/compile-test.rs | 7 ++++--- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 218b0d27f7486..9c508fc0e4a1a 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -173,13 +173,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { !preds.is_empty() && { let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_root_empty, ty); preds.iter().all(|t| { - let ty_params = &t - .skip_binder() - .trait_ref - .substs - .iter() - .skip(1) - .collect::>(); + let ty_params = &t.skip_binder().trait_ref.substs.iter().skip(1).collect::>(); implements_trait(cx, ty_empty_region, t.def_id(), ty_params) }) }, diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index dfa6223f1b9dd..5f794598052f6 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -279,13 +279,12 @@ impl EarlyLintPass for Write { if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) { if fmt_str.symbol == Symbol::intern("") { let mut applicability = Applicability::MachineApplicable; - let suggestion = expr.map_or_else( - move || { - applicability = Applicability::HasPlaceholders; - Cow::Borrowed("v") - }, - move |expr| snippet_with_applicability(cx, expr.span, "v", &mut applicability), - ); + let suggestion = if let Some(e) = expr { + snippet_with_applicability(cx, e.span, "v", &mut applicability) + } else { + applicability = Applicability::HasPlaceholders; + Cow::Borrowed("v") + }; span_lint_and_sugg( cx, diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 1c4914a470c9b..7bd5f09f333dd 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -153,9 +153,6 @@ fn run_ui_toml(config: &mut compiletest::Config) { } fn run_ui_cargo(config: &mut compiletest::Config) { - if cargo::is_rustc_test_suite() { - return; - } fn run_tests( config: &compiletest::Config, filter: &Option, @@ -216,6 +213,10 @@ fn run_ui_cargo(config: &mut compiletest::Config) { Ok(result) } + if cargo::is_rustc_test_suite() { + return; + } + config.mode = TestMode::Ui; config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap(); From 1fbc037da6fea06b572391f5e3fe24c6903d8dae Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 31 May 2020 14:09:15 +0200 Subject: [PATCH 490/695] Clean up E0622 explanation --- src/librustc_error_codes/error_codes/E0622.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0622.md b/src/librustc_error_codes/error_codes/E0622.md index 1de81dabb291f..990a25494129e 100644 --- a/src/librustc_error_codes/error_codes/E0622.md +++ b/src/librustc_error_codes/error_codes/E0622.md @@ -5,8 +5,7 @@ Erroneous code example: ```compile_fail,E0622 #![feature(intrinsics)] extern "rust-intrinsic" { - pub static breakpoint : unsafe extern "rust-intrinsic" fn(); - // error: intrinsic must be a function + pub static breakpoint : fn(); // error: intrinsic must be a function } fn main() { unsafe { breakpoint(); } } @@ -14,4 +13,13 @@ fn main() { unsafe { breakpoint(); } } An intrinsic is a function available for use in a given programming language whose implementation is handled specially by the compiler. In order to fix this -error, just declare a function. +error, just declare a function. Example: + +```no_run +#![feature(intrinsics)] +extern "rust-intrinsic" { + pub fn breakpoint(); // ok! +} + +fn main() { unsafe { breakpoint(); } } +``` From 7a2efa3a106389e9cd5c8bf3ab8f809398e77053 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 31 May 2020 14:27:33 +0200 Subject: [PATCH 491/695] Put input timeout clearance inside a function --- src/librustdoc/html/static/main.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index c349b59e562a9..6169d5ce8e85c 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -92,6 +92,13 @@ function getSearchElement() { var titleBeforeSearch = document.title; + function clearInputTimeout() { + if (searchTimeout !== null) { + clearTimeout(searchTimeout); + searchTimeout = null; + } + } + function getPageId() { var id = document.location.href.split("#")[1]; if (id) { @@ -345,10 +352,7 @@ function getSearchElement() { if (hasClass(help, "hidden") === false) { displayHelp(false, ev, help); } else if (hasClass(search, "hidden") === false) { - if (searchTimeout !== null) { - clearTimeout(searchTimeout); - searchTimeout = null; - } + clearInputTimeout(); ev.preventDefault(); hideSearchResults(search); document.title = titleBeforeSearch; @@ -1805,7 +1809,7 @@ function getSearchElement() { function startSearch() { var callback = function() { - clearTimeout(searchTimeout); + clearInputTimeout(); if (search_input.value.length === 0) { if (browserSupportsHistoryApi()) { history.replaceState("", window.currentCrate + " - Rust", "?search="); @@ -1819,10 +1823,7 @@ function getSearchElement() { search_input.oninput = callback; document.getElementsByClassName("search-form")[0].onsubmit = function(e) { e.preventDefault(); - if (searchTimeout !== null) { - clearTimeout(searchTimeout); - searchTimeout = null; - } + clearInputTimeout(); search(); }; search_input.onchange = function(e) { @@ -1831,10 +1832,7 @@ function getSearchElement() { return; } // Do NOT e.preventDefault() here. It will prevent pasting. - if (searchTimeout !== null) { - clearTimeout(searchTimeout); - searchTimeout = null; - } + clearInputTimeout(); // zero-timeout necessary here because at the time of event handler execution the // pasted content is not in the input field yet. Shouldn’t make any difference for // change, though. From e07e42433f9f8e2845d4941c59dc64918d467228 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 14:26:41 +0200 Subject: [PATCH 492/695] replace DUMMY_SP by proper span --- src/librustc_mir/transform/validate.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 046889193dac3..7a1393468cec6 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -54,12 +54,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // `Operand::Copy` is only supposed to be used with `Copy` types. if let Operand::Copy(place) = operand { let ty = place.ty(&self.body.local_decls, self.tcx).ty; + let span = self.body.source_info(location).span; - if !ty.is_copy_modulo_regions(self.tcx, self.param_env, DUMMY_SP) { - self.fail( - DUMMY_SP, - format!("`Operand::Copy` with non-`Copy` type {} at {:?}", ty, location), - ); + if !ty.is_copy_modulo_regions(self.tcx, self.param_env, span) { + self.fail(span, format!("`Operand::Copy` with non-`Copy` type {}", ty)); } } From 9a4bdbff9e52fe2bb2977ea6edddb13064726a25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 15:07:16 +0200 Subject: [PATCH 493/695] more checks for SwitchInt --- src/librustc_mir/transform/validate.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 7a1393468cec6..4039d1b50e8f5 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -90,11 +90,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { TerminatorKind::Goto { target } => { self.check_bb(terminator.source_info.span, *target); } - TerminatorKind::SwitchInt { targets, .. } => { - if targets.is_empty() { + TerminatorKind::SwitchInt { targets, values, .. } => { + if targets.len() != values.len() + 1 { self.fail( terminator.source_info.span, - "encountered `SwitchInt` terminator with no target to jump to", + format!( + "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)", + values.len(), + targets.len(), + ), ); } for target in targets { From f793c0b1bf3392c19eb11331fddc8c9f561361ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 15:21:09 +0200 Subject: [PATCH 494/695] always print MIR Location when validator finds a problem --- src/librustc_mir/transform/validate.rs | 68 ++++++++++++++------------ 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 4039d1b50e8f5..7d301b2f49648 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -9,7 +9,7 @@ use rustc_middle::{ }, ty::{self, ParamEnv, TyCtxt}, }; -use rustc_span::{def_id::DefId, Span, DUMMY_SP}; +use rustc_span::def_id::DefId; pub struct Validator { /// Describes at which point in the pipeline this validation is happening. @@ -33,18 +33,25 @@ struct TypeChecker<'a, 'tcx> { } impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - fn fail(&self, span: Span, msg: impl AsRef) { + fn fail(&self, location: Location, msg: impl AsRef) { + let span = self.body.source_info(location).span; // We use `delay_span_bug` as we might see broken MIR when other errors have already // occurred. self.tcx.sess.diagnostic().delay_span_bug( span, - &format!("broken MIR in {:?} ({}): {}", self.def_id, self.when, msg.as_ref()), + &format!( + "broken MIR in {:?} ({}) at {:?}:\n{}", + self.def_id, + self.when, + location, + msg.as_ref() + ), ); } - fn check_bb(&self, span: Span, bb: BasicBlock) { + fn check_bb(&self, location: Location, bb: BasicBlock) { if self.body.basic_blocks().get(bb).is_none() { - self.fail(span, format!("encountered jump to invalid basic block {:?}", bb)) + self.fail(location, format!("encountered jump to invalid basic block {:?}", bb)) } } } @@ -57,7 +64,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let span = self.body.source_info(location).span; if !ty.is_copy_modulo_regions(self.tcx, self.param_env, span) { - self.fail(span, format!("`Operand::Copy` with non-`Copy` type {}", ty)); + self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty)); } } @@ -72,11 +79,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => { if dest == src { self.fail( - DUMMY_SP, - format!( - "encountered `Assign` statement with overlapping memory at {:?}", - location - ), + location, + "encountered `Assign` statement with overlapping memory", ); } } @@ -85,15 +89,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _location: Location) { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { match &terminator.kind { TerminatorKind::Goto { target } => { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); } TerminatorKind::SwitchInt { targets, values, .. } => { if targets.len() != values.len() + 1 { self.fail( - terminator.source_info.span, + location, format!( "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)", values.len(), @@ -102,19 +106,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } for target in targets { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); } } TerminatorKind::Drop { target, unwind, .. } => { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); if let Some(unwind) = unwind { - self.check_bb(terminator.source_info.span, *unwind); + self.check_bb(location, *unwind); } } TerminatorKind::DropAndReplace { target, unwind, .. } => { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); if let Some(unwind) = unwind { - self.check_bb(terminator.source_info.span, *unwind); + self.check_bb(location, *unwind); } } TerminatorKind::Call { func, destination, cleanup, .. } => { @@ -122,52 +126,52 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { match func_ty.kind { ty::FnPtr(..) | ty::FnDef(..) => {} _ => self.fail( - terminator.source_info.span, + location, format!("encountered non-callable type {} in `Call` terminator", func_ty), ), } if let Some((_, target)) = destination { - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); } if let Some(cleanup) = cleanup { - self.check_bb(terminator.source_info.span, *cleanup); + self.check_bb(location, *cleanup); } } TerminatorKind::Assert { cond, target, cleanup, .. } => { let cond_ty = cond.ty(&self.body.local_decls, self.tcx); if cond_ty != self.tcx.types.bool { self.fail( - terminator.source_info.span, + location, format!( "encountered non-boolean condition of type {} in `Assert` terminator", cond_ty ), ); } - self.check_bb(terminator.source_info.span, *target); + self.check_bb(location, *target); if let Some(cleanup) = cleanup { - self.check_bb(terminator.source_info.span, *cleanup); + self.check_bb(location, *cleanup); } } TerminatorKind::Yield { resume, drop, .. } => { - self.check_bb(terminator.source_info.span, *resume); + self.check_bb(location, *resume); if let Some(drop) = drop { - self.check_bb(terminator.source_info.span, *drop); + self.check_bb(location, *drop); } } TerminatorKind::FalseEdges { real_target, imaginary_target } => { - self.check_bb(terminator.source_info.span, *real_target); - self.check_bb(terminator.source_info.span, *imaginary_target); + self.check_bb(location, *real_target); + self.check_bb(location, *imaginary_target); } TerminatorKind::FalseUnwind { real_target, unwind } => { - self.check_bb(terminator.source_info.span, *real_target); + self.check_bb(location, *real_target); if let Some(unwind) = unwind { - self.check_bb(terminator.source_info.span, *unwind); + self.check_bb(location, *unwind); } } TerminatorKind::InlineAsm { destination, .. } => { if let Some(destination) = destination { - self.check_bb(terminator.source_info.span, *destination); + self.check_bb(location, *destination); } } // Nothing to validate for these. From 0bcfae92f80d31cad4e5fb687da8033a38d06a32 Mon Sep 17 00:00:00 2001 From: djugei Date: Sun, 31 May 2020 15:41:33 +0200 Subject: [PATCH 495/695] moved cast_ptr_alignment to pedantic and expanded documentation --- clippy_lints/src/types.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 6ed9ff22e4664..3ac99e2468411 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -974,7 +974,8 @@ declare_clippy_lint! { /// behavior. /// /// **Known problems:** Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar - /// on the resulting pointer is fine. + /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like + /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. /// /// **Example:** /// ```rust @@ -982,7 +983,7 @@ declare_clippy_lint! { /// let _ = (&mut 1u8 as *mut u8) as *mut u16; /// ``` pub CAST_PTR_ALIGNMENT, - correctness, + pedantic, "cast from a pointer to a more-strictly-aligned pointer" } From 18b5ceed7991e3d8616b74b42de26330ca4c40db Mon Sep 17 00:00:00 2001 From: djugei Date: Sun, 31 May 2020 16:00:29 +0200 Subject: [PATCH 496/695] ran update_lints --- clippy_lints/src/lib.rs | 3 +-- src/lintlist/mod.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 902f3d56c1e4f..6475fa67d2518 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1164,6 +1164,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CAST_POSSIBLE_TRUNCATION), LintId::of(&types::CAST_POSSIBLE_WRAP), LintId::of(&types::CAST_PRECISION_LOSS), + LintId::of(&types::CAST_PTR_ALIGNMENT), LintId::of(&types::CAST_SIGN_LOSS), LintId::of(&types::IMPLICIT_HASHER), LintId::of(&types::INVALID_UPCAST_COMPARISONS), @@ -1410,7 +1411,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::ABSURD_EXTREME_COMPARISONS), LintId::of(&types::BORROWED_BOX), LintId::of(&types::BOX_VEC), - LintId::of(&types::CAST_PTR_ALIGNMENT), LintId::of(&types::CAST_REF_TO_MUT), LintId::of(&types::CHAR_LIT_AS_U8), LintId::of(&types::FN_TO_NUMERIC_CAST), @@ -1669,7 +1669,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&transmute::WRONG_TRANSMUTE), LintId::of(&transmuting_null::TRANSMUTING_NULL), LintId::of(&types::ABSURD_EXTREME_COMPARISONS), - LintId::of(&types::CAST_PTR_ALIGNMENT), LintId::of(&types::CAST_REF_TO_MUT), LintId::of(&types::UNIT_CMP), LintId::of(&unicode::ZERO_WIDTH_SPACE), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f63301c7db0a6..b9c84654593f9 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -166,7 +166,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "cast_ptr_alignment", - group: "correctness", + group: "pedantic", desc: "cast from a pointer to a more-strictly-aligned pointer", deprecation: None, module: "types", From 309661e84f04bedb247f42331b144a8d5ad9338d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 31 May 2020 16:22:23 +0200 Subject: [PATCH 497/695] InstCombine: Don't optimize `&mut *x` into `x` --- src/librustc_mir/transform/instcombine.rs | 18 ++++++++---------- .../rustc.a.Inline.after.mir | 6 +++++- .../rustc.b.Inline.after.mir | 8 ++++++-- .../rustc.nrvo.RenameReturnPlace.diff | 7 ++++++- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index a016892d982d1..7967137e01e54 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -1,11 +1,12 @@ //! Performs various peephole optimizations. use crate::transform::{MirPass, MirSource}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::Mutability; use rustc_index::vec::Idx; use rustc_middle::mir::visit::{MutVisitor, Visitor}; use rustc_middle::mir::{ - Body, Constant, Local, Location, Mutability, Operand, Place, PlaceRef, ProjectionElem, Rvalue, + Body, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, }; use rustc_middle::ty::{self, TyCtxt}; use std::mem; @@ -39,7 +40,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { } fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { - if let Some(mtbl) = self.optimizations.and_stars.remove(&location) { + if self.optimizations.and_stars.remove(&location) { debug!("replacing `&*`: {:?}", rvalue); let new_place = match rvalue { Rvalue::Ref(_, _, place) => { @@ -57,10 +58,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { } _ => bug!("Detected `&*` but didn't find `&*`!"), }; - *rvalue = Rvalue::Use(match mtbl { - Mutability::Mut => Operand::Move(new_place), - Mutability::Not => Operand::Copy(new_place), - }); + *rvalue = Rvalue::Use(Operand::Copy(new_place)) } if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { @@ -93,8 +91,8 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { { // The dereferenced place must have type `&_`. let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty; - if let ty::Ref(_, _, mtbl) = ty.kind { - self.optimizations.and_stars.insert(location, mtbl); + if let ty::Ref(_, _, Mutability::Not) = ty.kind { + self.optimizations.and_stars.insert(location); } } } @@ -114,6 +112,6 @@ impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { #[derive(Default)] struct OptimizationList<'tcx> { - and_stars: FxHashMap, + and_stars: FxHashSet, arrays_lengths: FxHashMap>, } diff --git a/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.a.Inline.after.mir b/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.a.Inline.after.mir index 8751469d265a2..44f412c2e2674 100644 --- a/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.a.Inline.after.mir +++ b/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.a.Inline.after.mir @@ -8,6 +8,7 @@ fn a(_1: &mut [T]) -> &mut [T] { let mut _4: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 scope 1 { debug self => _4; // in scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + let mut _5: &mut [T]; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 } bb0: { @@ -15,7 +16,10 @@ fn a(_1: &mut [T]) -> &mut [T] { StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 - _3 = move _4; // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + StorageLive(_5); // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + _5 = &mut (*_4); // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + _3 = &mut (*_5); // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + StorageDead(_5); // scope 1 at $SRC_DIR/libcore/convert/mod.rs:LL:COL _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:14: 3:15 _0 = &mut (*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 diff --git a/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.b.Inline.after.mir b/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.b.Inline.after.mir index 743da27a049f9..48e48f989bd94 100644 --- a/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue-58867-inline-as-ref-as-mut/rustc.b.Inline.after.mir @@ -9,6 +9,7 @@ fn b(_1: &mut std::boxed::Box) -> &mut T { scope 1 { debug self => _4; // in scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL let mut _5: &mut T; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + let mut _6: &mut T; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 } bb0: { @@ -17,8 +18,11 @@ fn b(_1: &mut std::boxed::Box) -> &mut T { StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 StorageLive(_5); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL - _5 = &mut (*(*_4)); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL - _3 = move _5; // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL + StorageLive(_6); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL + _6 = &mut (*(*_4)); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL + _5 = &mut (*_6); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL + _3 = &mut (*_5); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL + StorageDead(_6); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL StorageDead(_5); // scope 1 at $SRC_DIR/liballoc/boxed.rs:LL:COL _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:14: 8:15 diff --git a/src/test/mir-opt/nrvo-simple/rustc.nrvo.RenameReturnPlace.diff b/src/test/mir-opt/nrvo-simple/rustc.nrvo.RenameReturnPlace.diff index 79d92897cb572..4511470f3a50f 100644 --- a/src/test/mir-opt/nrvo-simple/rustc.nrvo.RenameReturnPlace.diff +++ b/src/test/mir-opt/nrvo-simple/rustc.nrvo.RenameReturnPlace.diff @@ -26,12 +26,17 @@ // + span: $DIR/nrvo-simple.rs:3:20: 3:21 // + literal: Const { ty: u8, val: Value(Scalar(0x00)) } StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 + StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 + StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 + _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - _3 = move _1(move _6) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 + _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 + _3 = move _1(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 } bb1: { + StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:4:18: 4:19 + StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 - _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:5:5: 5:8 - StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:6:1: 6:2 From 9f83d36edcfeabad63e95338c17942a36f072782 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 31 May 2020 17:16:44 +0200 Subject: [PATCH 498/695] remove trivial calls to mk_const --- src/librustc_middle/ty/structural_impls.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index c6ecb08615fcf..aa47c6b70a21a 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -1019,7 +1019,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { let ty = self.ty.fold_with(folder); let val = self.val.fold_with(folder); - folder.tcx().mk_const(ty::Const { ty, val }) + if ty != self.ty || val != self.val { + folder.tcx().mk_const(ty::Const { ty, val }) + } else { + *self + } } fn fold_with>(&self, folder: &mut F) -> Self { From a367956100e1a008906c0a9e251187f1d4203dde Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Wed, 27 May 2020 21:58:12 +0200 Subject: [PATCH 499/695] Make remote-test-client and remote-test-server compatible with windows `compiletest` and `remote-test-client`: The command line for `remote-test-client` was changed slightly to allow cross-platform compatible paths. The old way of supplying the support libs was by joining their paths with the executable path with `:`. This caused Windows-style paths to be split after the directory letter. Now, the number of support libs is provided as a parameter as well, and the support lib paths are split off from the regular args in the client. `remote-test-server`: - Marked Unix-only parts as such and implemented Windows alternatives - On Windows `LD_LIBRARY_PATH` doesn't exist. Libraries are loaded from `PATH` though, so that's the way around it. - Tiny cleanup: `Command::args`/`envs` instead of manually looping over them - The temp path for Windows has to be set via environment variable, since there isn't a global temp directory that would work on every machine (as a static string) --- src/tools/compiletest/src/runtest.rs | 22 ++++--- src/tools/remote-test-client/src/main.rs | 14 ++-- src/tools/remote-test-server/src/main.rs | 83 +++++++++++++++++------- 3 files changed, 83 insertions(+), 36 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 63fd052a5560d..a6995eb820a78 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1584,29 +1584,35 @@ impl<'test> TestCx<'test> { // // into // - // remote-test-client run program:support-lib.so arg1 arg2 + // remote-test-client run program 2 support-lib.so support-lib2.so arg1 arg2 // // The test-client program will upload `program` to the emulator // along with all other support libraries listed (in this case - // `support-lib.so`. It will then execute the program on the - // emulator with the arguments specified (in the environment we give - // the process) and then report back the same result. + // `support-lib.so` and `support-lib2.so`. It will then execute + // the program on the emulator with the arguments specified + // (in the environment we give the process) and then report back + // the same result. _ if self.config.remote_test_client.is_some() => { let aux_dir = self.aux_output_dir_name(); - let ProcArgs { mut prog, args } = self.make_run_args(); + let ProcArgs { prog, args } = self.make_run_args(); + let mut support_libs = Vec::new(); if let Ok(entries) = aux_dir.read_dir() { for entry in entries { let entry = entry.unwrap(); if !entry.path().is_file() { continue; } - prog.push_str(":"); - prog.push_str(entry.path().to_str().unwrap()); + support_libs.push(entry.path()); } } let mut test_client = Command::new(self.config.remote_test_client.as_ref().unwrap()); - test_client.args(&["run", &prog]).args(args).envs(env.clone()); + test_client + .args(&["run", &prog]) + .arg(support_libs.len().to_string()) + .args(support_libs) + .args(args) + .envs(env.clone()); self.compose_and_run( test_client, self.config.run_lib_path.to_str().unwrap(), diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index 3379d82eda829..dea8bb933c9d9 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -44,7 +44,11 @@ fn main() { args.next().map(|s| s.into()), ), "push" => push(Path::new(&args.next().unwrap())), - "run" => run(args.next().unwrap(), args.collect()), + "run" => run( + args.next().unwrap(), + args.next().and_then(|count| count.parse().ok()).unwrap(), + args.collect(), + ), "help" | "-h" | "--help" => help(), cmd => { println!("unknown command: {}", cmd); @@ -197,12 +201,14 @@ fn push(path: &Path) { println!("done pushing {:?}", path); } -fn run(files: String, args: Vec) { +fn run(exe: String, support_lib_count: usize, all_args: Vec) { let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string()); let client = t!(TcpStream::connect(device_address)); let mut client = BufWriter::new(client); t!(client.write_all(b"run ")); + let (support_libs, args) = all_args.split_at(support_lib_count); + // Send over the args for arg in args { t!(client.write_all(arg.as_bytes())); @@ -227,9 +233,7 @@ fn run(files: String, args: Vec) { t!(client.write_all(&[0])); // Send over support libraries - let mut files = files.split(':'); - let exe = files.next().unwrap(); - for file in files.map(Path::new) { + for file in support_libs.iter().map(Path::new) { send(&file, &mut client); } t!(client.write_all(&[0])); diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index 826e3d05111ae..d9f65cf502da6 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -12,15 +12,19 @@ #![deny(warnings)] +#[cfg(not(windows))] +use std::fs::Permissions; +#[cfg(not(windows))] +use std::os::unix::prelude::*; + use std::cmp; use std::env; -use std::fs::{self, File, Permissions}; +use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufReader}; use std::net::{TcpListener, TcpStream}; -use std::os::unix::prelude::*; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Command, ExitStatus, Stdio}; use std::str; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; @@ -72,21 +76,23 @@ fn main() { let config = Config::parse_args(); - let bind_addr = if cfg!(target_os = "android") || config.remote { + let bind_addr = if cfg!(target_os = "android") || cfg!(windows) || config.remote { "0.0.0.0:12345" } else { "10.0.2.15:12345" }; - let (listener, work) = if cfg!(target_os = "android") { - (t!(TcpListener::bind(bind_addr)), "/data/tmp/work") + let listener = t!(TcpListener::bind(bind_addr)); + let work: PathBuf = if cfg!(windows) { + env::var_os("RUST_TEMP").expect("Set RUST_TEMP to your preferred temp folder").into() + } else if cfg!(target_os = "android") { + "/data/tmp/work".into() } else { - (t!(TcpListener::bind(bind_addr)), "/tmp/work") + "/tmp/work".into() }; println!("listening!"); - let work = Path::new(work); - t!(fs::create_dir_all(work)); + t!(fs::create_dir_all(&work)); let lock = Arc::new(Mutex::new(())); @@ -99,10 +105,11 @@ fn main() { if &buf[..] == b"ping" { t!(socket.write_all(b"pong")); } else if &buf[..] == b"push" { - handle_push(socket, work); + handle_push(socket, &work); } else if &buf[..] == b"run " { let lock = lock.clone(); - thread::spawn(move || handle_run(socket, work, &lock)); + let work = work.clone(); + thread::spawn(move || handle_run(socket, &work, &lock)); } else { panic!("unknown command {:?}", buf); } @@ -196,17 +203,28 @@ fn handle_run(socket: TcpStream, work: &Path, lock: &Mutex<()>) { let exe = recv(&path, &mut reader); let mut cmd = Command::new(&exe); - for arg in args { - cmd.arg(arg); - } - for (k, v) in env { - cmd.env(k, v); - } + cmd.args(args); + cmd.envs(env); // Support libraries were uploaded to `work` earlier, so make sure that's // in `LD_LIBRARY_PATH`. Also include our own current dir which may have // had some libs uploaded. - cmd.env("LD_LIBRARY_PATH", format!("{}:{}", work.display(), path.display())); + if cfg!(windows) { + // On windows, libraries are just searched in the executable directory, + // system directories, PWD, and PATH, in that order. PATH is the only one + // we can change for this. + cmd.env( + "PATH", + env::join_paths( + std::iter::once(work.to_owned()) + .chain(std::iter::once(path.clone())) + .chain(env::split_paths(&env::var_os("PATH").unwrap())), + ) + .unwrap(), + ); + } else { + cmd.env("LD_LIBRARY_PATH", format!("{}:{}", work.display(), path.display())); + } // Spawn the child and ferry over stdout/stderr to the socket in a framed // fashion (poor man's style) @@ -223,10 +241,9 @@ fn handle_run(socket: TcpStream, work: &Path, lock: &Mutex<()>) { // Finally send over the exit status. let status = t!(child.wait()); - let (which, code) = match status.code() { - Some(n) => (0, n), - None => (1, status.signal().unwrap()), - }; + + let (which, code) = get_status_code(&status); + t!(socket.lock().unwrap().write_all(&[ which, (code >> 24) as u8, @@ -236,6 +253,19 @@ fn handle_run(socket: TcpStream, work: &Path, lock: &Mutex<()>) { ])); } +#[cfg(not(windows))] +fn get_status_code(status: &ExitStatus) -> (u8, i32) { + match status.code() { + Some(n) => (0, n), + None => (1, status.signal().unwrap()), + } +} + +#[cfg(windows)] +fn get_status_code(status: &ExitStatus) -> (u8, i32) { + (0, status.code().unwrap()) +} + fn recv(dir: &Path, io: &mut B) -> PathBuf { let mut filename = Vec::new(); t!(io.read_until(0, &mut filename)); @@ -253,10 +283,17 @@ fn recv(dir: &Path, io: &mut B) -> PathBuf { let dst = dir.join(t!(str::from_utf8(&filename[..len]))); let amt = read_u32(io) as u64; t!(io::copy(&mut io.take(amt), &mut t!(File::create(&dst)))); - t!(fs::set_permissions(&dst, Permissions::from_mode(0o755))); + set_permissions(&dst); dst } +#[cfg(not(windows))] +fn set_permissions(path: &Path) { + t!(fs::set_permissions(&dst, Permissions::from_mode(0o755))); +} +#[cfg(windows)] +fn set_permissions(_path: &Path) {} + fn my_copy(src: &mut dyn Read, which: u8, dst: &Mutex) { let mut b = [0; 1024]; loop { From 41d540fcb72ccef0e1c20f145288993a41260e25 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Thu, 28 May 2020 10:04:43 +0200 Subject: [PATCH 500/695] Unify temp path generation for non-android --- src/tools/remote-test-server/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index d9f65cf502da6..9112985e140a7 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -83,12 +83,12 @@ fn main() { }; let listener = t!(TcpListener::bind(bind_addr)); - let work: PathBuf = if cfg!(windows) { - env::var_os("RUST_TEMP").expect("Set RUST_TEMP to your preferred temp folder").into() - } else if cfg!(target_os = "android") { + let work: PathBuf = if cfg!(target_os = "android") { "/data/tmp/work".into() } else { - "/tmp/work".into() + let mut temp_dir = env::temp_dir(); + temp_dir.push("work"); + temp_dir }; println!("listening!"); From 577ac2f836f860646ca4f47a5effcfe6f024ec39 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Fri, 29 May 2020 11:57:23 +0200 Subject: [PATCH 501/695] Fix `set_permissions` call for non-windows --- src/tools/remote-test-server/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs index 9112985e140a7..e7eff35e55725 100644 --- a/src/tools/remote-test-server/src/main.rs +++ b/src/tools/remote-test-server/src/main.rs @@ -289,7 +289,7 @@ fn recv(dir: &Path, io: &mut B) -> PathBuf { #[cfg(not(windows))] fn set_permissions(path: &Path) { - t!(fs::set_permissions(&dst, Permissions::from_mode(0o755))); + t!(fs::set_permissions(&path, Permissions::from_mode(0o755))); } #[cfg(windows)] fn set_permissions(_path: &Path) {} From 0199fdc0f72ec6942d93d0bf23c7fa1fb9fbf54f Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 31 May 2020 15:20:52 +0200 Subject: [PATCH 502/695] Update help text of remote-test-client to reflect changed command --- src/tools/remote-test-client/src/main.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index dea8bb933c9d9..88eaaac287b81 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -306,7 +306,8 @@ Usage: {0} [] Sub-commands: spawn-emulator [rootfs] See below push Copy to emulator - run [args...] Run program on emulator + run [support_libs...] [args...] + Run program on emulator help Display help message Spawning an emulator: @@ -325,8 +326,8 @@ specified. The file at is sent to this target. Executing commands on a running emulator: First the target emulator/adb session is connected to as for pushing files. Next -the colon separated list of is pushed to the target. Finally, the first -file in is executed in the emulator, preserving the current environment. +the and any specified support libs are pushed to the target. Finally, the + is executed in the emulator, preserving the current environment. That command's status code is returned. ", env::args().next().unwrap(), From 036da3a6dcc084db90dbe6ea2831eb7332a1c535 Mon Sep 17 00:00:00 2001 From: Dennis Duda Date: Sun, 31 May 2020 17:36:17 +0200 Subject: [PATCH 503/695] Make `remote-test-client` work as cargo runner again Since cargo appends executable/args, the support_lib count parameter has to come first. --- src/bootstrap/test.rs | 2 +- src/tools/compiletest/src/runtest.rs | 3 +-- src/tools/remote-test-client/src/main.rs | 8 +++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index f1305e2540b4c..3ae6c34d22841 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1762,7 +1762,7 @@ impl Step for Crate { } else if builder.remote_tested(target) { cargo.env( format!("CARGO_TARGET_{}_RUNNER", envify(&target)), - format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display()), + format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()), ); } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a6995eb820a78..4f8cf92b86938 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1608,8 +1608,7 @@ impl<'test> TestCx<'test> { let mut test_client = Command::new(self.config.remote_test_client.as_ref().unwrap()); test_client - .args(&["run", &prog]) - .arg(support_libs.len().to_string()) + .args(&["run", &support_libs.len().to_string(), &prog]) .args(support_libs) .args(args) .envs(env.clone()); diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index 88eaaac287b81..259477e9a1c36 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -45,8 +45,10 @@ fn main() { ), "push" => push(Path::new(&args.next().unwrap())), "run" => run( - args.next().unwrap(), args.next().and_then(|count| count.parse().ok()).unwrap(), + // the last required parameter must remain the executable + // path so that the client works as a cargo runner + args.next().unwrap(), args.collect(), ), "help" | "-h" | "--help" => help(), @@ -201,7 +203,7 @@ fn push(path: &Path) { println!("done pushing {:?}", path); } -fn run(exe: String, support_lib_count: usize, all_args: Vec) { +fn run(support_lib_count: usize, exe: String, all_args: Vec) { let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string()); let client = t!(TcpStream::connect(device_address)); let mut client = BufWriter::new(client); @@ -306,7 +308,7 @@ Usage: {0} [] Sub-commands: spawn-emulator [rootfs] See below push Copy to emulator - run [support_libs...] [args...] + run [support_libs...] [args...] Run program on emulator help Display help message From 6122612232976c1ac766a5d415265eb3eb30e72c Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sun, 31 May 2020 17:38:59 +0200 Subject: [PATCH 504/695] Increase cargo_metadata version to 0.9.1 `clippy_lints` makes use of `dep_kinds` on `NodeDep` but this was only added in versoin 0.9.1. Compiling with 0.9.0 will fail because of this. --- Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6999b6bd74040..836897927b015 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ tempfile = { version = "3.1.0", optional = true } lazy_static = "1.0" [dev-dependencies] -cargo_metadata = "0.9.0" +cargo_metadata = "0.9.1" compiletest_rs = { version = "0.5.0", features = ["tmp"] } tester = "0.7" lazy_static = "1.0" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 76baf27fb2dbf..98391732d1893 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -17,7 +17,7 @@ keywords = ["clippy", "lint", "plugin"] edition = "2018" [dependencies] -cargo_metadata = "0.9.0" +cargo_metadata = "0.9.1" if_chain = "1.0.0" itertools = "0.9" lazy_static = "1.0.2" From 0ab823c509897ce2f516feb760fe1bf02cf77443 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 26 Aug 2019 18:34:30 +0200 Subject: [PATCH 505/695] Rework suggestion generation of `unit_arg` lint --- clippy_lints/src/types.rs | 42 ++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 3ac99e2468411..8fcca4b7bb9ca 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -779,6 +779,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { match expr.kind { ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) => { + let mut args_to_recover = vec![]; for arg in args { if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) { if let ExprKind::Match(.., match_source) = &arg.kind { @@ -787,17 +788,40 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { } } - span_lint_and_sugg( - cx, - UNIT_ARG, - arg.span, - "passing a unit value to a function", - "if you intended to pass a unit value, use a unit literal instead", - "()".to_string(), - Applicability::MaybeIncorrect, - ); + args_to_recover.push(arg); } } + if !args_to_recover.is_empty() { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_then(cx, UNIT_ARG, expr.span, "passing a unit value to a function", |db| { + db.span_suggestion( + expr.span.with_hi(expr.span.lo()), + "move the expressions in front of the call...", + format!( + "{} ", + args_to_recover + .iter() + .map(|arg| { + format!( + "{};", + snippet_with_applicability(cx, arg.span, "..", &mut applicability) + ) + }) + .collect::>() + .join(" ") + ), + applicability, + ); + db.multipart_suggestion( + "...and use unit literals instead", + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::>(), + applicability, + ); + }); + } }, _ => (), } From 380d941a045dc213ae28807d74fc32d1b1841e22 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 26 Aug 2019 19:35:25 +0200 Subject: [PATCH 506/695] Adapt stderr and fixed files --- tests/ui/unit_arg.fixed | 29 +++++++--- tests/ui/unit_arg.rs | 10 +++- tests/ui/unit_arg.stderr | 112 ++++++++++++++++++++++++++++++--------- 3 files changed, 118 insertions(+), 33 deletions(-) diff --git a/tests/ui/unit_arg.fixed b/tests/ui/unit_arg.fixed index a739cf7ad814e..67c6bdf8873b6 100644 --- a/tests/ui/unit_arg.fixed +++ b/tests/ui/unit_arg.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(unused_braces, clippy::no_effect, unused_must_use)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] use std::fmt::Debug; @@ -21,13 +21,21 @@ impl Bar { } fn bad() { - foo(()); - foo(()); - foo(()); - foo(()); - foo3((), 2, 2); + {}; foo(()); + { + 1; + }; foo(()); + foo(1); foo(()); + { + foo(1); + foo(2); + }; foo(()); + {}; foo3((), 2, 2); let b = Bar; - b.bar(()); + { + 1; + }; b.bar(()); + foo(0); foo(1); taking_multiple_units((), ()); } fn ok() { @@ -58,6 +66,13 @@ mod issue_2945 { } } +#[allow(dead_code)] +fn returning_expr() -> Option<()> { + foo(1); Some(()) +} + +fn taking_multiple_units(a: (), b: ()) {} + fn main() { bad(); ok(); diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index d90c49f79de62..c6e465b2e4c4b 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::unit_arg)] -#![allow(unused_braces, clippy::no_effect, unused_must_use)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] use std::fmt::Debug; @@ -35,6 +35,7 @@ fn bad() { b.bar({ 1; }); + taking_multiple_units(foo(0), foo(1)); } fn ok() { @@ -65,6 +66,13 @@ mod issue_2945 { } } +#[allow(dead_code)] +fn returning_expr() -> Option<()> { + Some(foo(1)) +} + +fn taking_multiple_units(a: (), b: ()) {} + fn main() { bad(); ok(); diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 21ccc684ea9de..ce9ab2f1271a7 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,79 +1,141 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:24:9 + --> $DIR/unit_arg.rs:24:5 | LL | foo({}); - | ^^ + | ^^^^^^^ | = note: `-D clippy::unit-arg` implied by `-D warnings` -help: if you intended to pass a unit value, use a unit literal instead +help: move the expressions in front of the call... + | +LL | {}; foo({}); + | ^^^ +help: ...and use unit literals instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:25:9 + --> $DIR/unit_arg.rs:25:5 | -LL | foo({ - | _________^ +LL | / foo({ LL | | 1; LL | | }); - | |_____^ + | |______^ + | +help: move the expressions in front of the call... + | +LL | { +LL | 1; +LL | }; foo({ | -help: if you intended to pass a unit value, use a unit literal instead +help: ...and use unit literals instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:28:9 + --> $DIR/unit_arg.rs:28:5 | LL | foo(foo(1)); - | ^^^^^^ + | ^^^^^^^^^^^ | -help: if you intended to pass a unit value, use a unit literal instead +help: move the expressions in front of the call... + | +LL | foo(1); foo(foo(1)); + | ^^^^^^^ +help: ...and use unit literals instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:29:9 + --> $DIR/unit_arg.rs:29:5 | -LL | foo({ - | _________^ +LL | / foo({ LL | | foo(1); LL | | foo(2); LL | | }); - | |_____^ + | |______^ + | +help: move the expressions in front of the call... + | +LL | { +LL | foo(1); +LL | foo(2); +LL | }; foo({ | -help: if you intended to pass a unit value, use a unit literal instead +help: ...and use unit literals instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:10 + --> $DIR/unit_arg.rs:33:5 | LL | foo3({}, 2, 2); - | ^^ + | ^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call... | -help: if you intended to pass a unit value, use a unit literal instead +LL | {}; foo3({}, 2, 2); + | ^^^ +help: ...and use unit literals instead | LL | foo3((), 2, 2); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:35:11 + --> $DIR/unit_arg.rs:35:5 | -LL | b.bar({ - | ___________^ +LL | / b.bar({ LL | | 1; LL | | }); - | |_____^ + | |______^ + | +help: move the expressions in front of the call... | -help: if you intended to pass a unit value, use a unit literal instead +LL | { +LL | 1; +LL | }; b.bar({ + | +help: ...and use unit literals instead | LL | b.bar(()); | ^^ -error: aborting due to 6 previous errors +error: passing a unit value to a function + --> $DIR/unit_arg.rs:38:5 + | +LL | taking_multiple_units(foo(0), foo(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call... + | +LL | foo(0); foo(1); taking_multiple_units(foo(0), foo(1)); + | ^^^^^^^^^^^^^^^ +help: ...and use unit literals instead + | +LL | taking_multiple_units((), foo(1)); + | ^^ +help: ...and use unit literals instead + | +LL | taking_multiple_units(foo(0), ()); + | ^^ + +error: passing a unit value to a function + --> $DIR/unit_arg.rs:71:5 + | +LL | Some(foo(1)) + | ^^^^^^^^^^^^ + | +help: move the expressions in front of the call... + | +LL | foo(1); Some(foo(1)) + | ^^^^^^^ +help: ...and use unit literals instead + | +LL | Some(()) + | ^^ + +error: aborting due to 8 previous errors From a1a1a4b82a35b810570dbf7d2ee7f00896bee232 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 26 Aug 2019 21:43:29 +0200 Subject: [PATCH 507/695] Use multiple span_suggestions instead of multipart_suggestion multipart suggestions aren't autofixable by rustfix yet --- clippy_lints/src/types.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 8fcca4b7bb9ca..3fbea77757dae 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -812,14 +812,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { ), applicability, ); - db.multipart_suggestion( - "...and use unit literals instead", - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::>(), - applicability, - ); + for arg in args_to_recover { + db.span_suggestion( + arg.span, + "...and use unit literals instead", + "()".to_string(), + applicability, + ); + } }); } }, From 0f69cafc2dd77d573e24870887a4a13cfe50515a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 17 Feb 2020 18:10:59 +0100 Subject: [PATCH 508/695] Rework suggestion generation and use multipart_suggestion again --- clippy_lints/src/types.rs | 55 +++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 3fbea77757dae..c95bd5d72bcd6 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -794,32 +794,43 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { if !args_to_recover.is_empty() { let mut applicability = Applicability::MachineApplicable; span_lint_and_then(cx, UNIT_ARG, expr.span, "passing a unit value to a function", |db| { + let sugg = args_to_recover + .iter() + .enumerate() + .map(|(i, arg)| { + let indent = if i == 0 { + 0 + } else { + indent_of(cx, expr.span).unwrap_or(0) + }; + format!( + "{}{};", + " ".repeat(indent), + snippet_block_with_applicability( + cx, + arg.span, + "..", + Some(expr.span), + &mut applicability + ) + ) + }) + .collect::>() + .join("\n"); db.span_suggestion( expr.span.with_hi(expr.span.lo()), - "move the expressions in front of the call...", - format!( - "{} ", - args_to_recover - .iter() - .map(|arg| { - format!( - "{};", - snippet_with_applicability(cx, arg.span, "..", &mut applicability) - ) - }) - .collect::>() - .join(" ") - ), + &format!("{}move the expressions in front of the call...", or), + format!("{}\n", sugg), + applicability, + ); + db.multipart_suggestion( + "...and use unit literals instead", + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::>(), applicability, ); - for arg in args_to_recover { - db.span_suggestion( - arg.span, - "...and use unit literals instead", - "()".to_string(), - applicability, - ); - } }); } }, From f9c325f5b657e0c37ba2016a51cddbeab7f7693f Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 17 Feb 2020 18:11:50 +0100 Subject: [PATCH 509/695] Suggest to remove the semicolon of the last stmt in a block --- clippy_lints/src/types.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index c95bd5d72bcd6..51d7d9b3ab713 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -794,6 +794,36 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { if !args_to_recover.is_empty() { let mut applicability = Applicability::MachineApplicable; span_lint_and_then(cx, UNIT_ARG, expr.span, "passing a unit value to a function", |db| { + let mut or = ""; + args_to_recover + .iter() + .filter_map(|arg| { + if_chain! { + if let ExprKind::Block(block, _) = arg.kind; + if block.expr.is_none(); + if let Some(last_stmt) = block.stmts.iter().last(); + if let StmtKind::Semi(last_expr) = last_stmt.kind; + if let Some(snip) = snippet_opt(cx, last_expr.span); + then { + Some(( + last_stmt.span, + snip, + )) + } + else { + None + } + } + }) + .for_each(|(span, sugg)| { + db.span_suggestion( + span, + "remove the semicolon from the last statement in the block", + sugg, + Applicability::MaybeIncorrect, + ); + or = "or "; + }); let sugg = args_to_recover .iter() .enumerate() From 4c9cefa12232aa0224b1680f51654fe10f5cf3b7 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 18 Feb 2020 09:51:52 +0100 Subject: [PATCH 510/695] Move linting out in its own function --- clippy_lints/src/types.rs | 171 ++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 80 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 51d7d9b3ab713..6866635b904be 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -779,89 +779,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { match expr.kind { ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) => { - let mut args_to_recover = vec![]; - for arg in args { - if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) { - if let ExprKind::Match(.., match_source) = &arg.kind { - if *match_source == MatchSource::TryDesugar { - continue; + let args_to_recover = args + .iter() + .filter(|arg| { + if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) { + if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind { + false + } else { + true } + } else { + false } - - args_to_recover.push(arg); - } - } + }) + .collect::>(); if !args_to_recover.is_empty() { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_then(cx, UNIT_ARG, expr.span, "passing a unit value to a function", |db| { - let mut or = ""; - args_to_recover - .iter() - .filter_map(|arg| { - if_chain! { - if let ExprKind::Block(block, _) = arg.kind; - if block.expr.is_none(); - if let Some(last_stmt) = block.stmts.iter().last(); - if let StmtKind::Semi(last_expr) = last_stmt.kind; - if let Some(snip) = snippet_opt(cx, last_expr.span); - then { - Some(( - last_stmt.span, - snip, - )) - } - else { - None - } - } - }) - .for_each(|(span, sugg)| { - db.span_suggestion( - span, - "remove the semicolon from the last statement in the block", - sugg, - Applicability::MaybeIncorrect, - ); - or = "or "; - }); - let sugg = args_to_recover - .iter() - .enumerate() - .map(|(i, arg)| { - let indent = if i == 0 { - 0 - } else { - indent_of(cx, expr.span).unwrap_or(0) - }; - format!( - "{}{};", - " ".repeat(indent), - snippet_block_with_applicability( - cx, - arg.span, - "..", - Some(expr.span), - &mut applicability - ) - ) - }) - .collect::>() - .join("\n"); - db.span_suggestion( - expr.span.with_hi(expr.span.lo()), - &format!("{}move the expressions in front of the call...", or), - format!("{}\n", sugg), - applicability, - ); - db.multipart_suggestion( - "...and use unit literals instead", - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::>(), - applicability, - ); - }); + lint_unit_args(cx, expr, &args_to_recover); } }, _ => (), @@ -869,6 +802,84 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { } } +fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + let (singular, plural) = if args_to_recover.len() > 1 { + ("", "s") + } else { + ("a ", "") + }; + span_lint_and_then( + cx, + UNIT_ARG, + expr.span, + &format!("passing {}unit value{} to a function", singular, plural), + |db| { + let mut or = ""; + args_to_recover + .iter() + .filter_map(|arg| { + if_chain! { + if let ExprKind::Block(block, _) = arg.kind; + if block.expr.is_none(); + if let Some(last_stmt) = block.stmts.iter().last(); + if let StmtKind::Semi(last_expr) = last_stmt.kind; + if let Some(snip) = snippet_opt(cx, last_expr.span); + then { + Some(( + last_stmt.span, + snip, + )) + } + else { + None + } + } + }) + .for_each(|(span, sugg)| { + db.span_suggestion( + span, + "remove the semicolon from the last statement in the block", + sugg, + Applicability::MaybeIncorrect, + ); + or = "or "; + }); + let sugg = args_to_recover + .iter() + .enumerate() + .map(|(i, arg)| { + let indent = if i == 0 { + 0 + } else { + indent_of(cx, expr.span).unwrap_or(0) + }; + format!( + "{}{};", + " ".repeat(indent), + snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability) + ) + }) + .collect::>() + .join("\n"); + db.span_suggestion( + expr.span.with_hi(expr.span.lo()), + &format!("{}move the expression{} in front of the call...", or, plural), + format!("{}\n", sugg), + applicability, + ); + db.multipart_suggestion( + &format!("...and use {}unit literal{} instead", singular, plural), + args_to_recover + .iter() + .map(|arg| (arg.span, "()".to_string())) + .collect::>(), + applicability, + ); + }, + ); +} + fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::DesugaringKind; if let ExprKind::Call(ref callee, _) = expr.kind { From 6d15a149640e5647ce232690d54b540346fa1641 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 17 Feb 2020 18:12:01 +0100 Subject: [PATCH 511/695] Update test files --- tests/ui/unit_arg.fixed | 79 -------------------- tests/ui/unit_arg.rs | 15 +++- tests/ui/unit_arg.stderr | 152 ++++++++++++++++++++++++++++----------- 3 files changed, 125 insertions(+), 121 deletions(-) delete mode 100644 tests/ui/unit_arg.fixed diff --git a/tests/ui/unit_arg.fixed b/tests/ui/unit_arg.fixed deleted file mode 100644 index 67c6bdf8873b6..0000000000000 --- a/tests/ui/unit_arg.fixed +++ /dev/null @@ -1,79 +0,0 @@ -// run-rustfix -#![warn(clippy::unit_arg)] -#![allow(clippy::no_effect, unused_must_use, unused_variables)] - -use std::fmt::Debug; - -fn foo(t: T) { - println!("{:?}", t); -} - -fn foo3(t1: T1, t2: T2, t3: T3) { - println!("{:?}, {:?}, {:?}", t1, t2, t3); -} - -struct Bar; - -impl Bar { - fn bar(&self, t: T) { - println!("{:?}", t); - } -} - -fn bad() { - {}; foo(()); - { - 1; - }; foo(()); - foo(1); foo(()); - { - foo(1); - foo(2); - }; foo(()); - {}; foo3((), 2, 2); - let b = Bar; - { - 1; - }; b.bar(()); - foo(0); foo(1); taking_multiple_units((), ()); -} - -fn ok() { - foo(()); - foo(1); - foo({ 1 }); - foo3("a", 3, vec![3]); - let b = Bar; - b.bar({ 1 }); - b.bar(()); - question_mark(); -} - -fn question_mark() -> Result<(), ()> { - Ok(Ok(())?)?; - Ok(Ok(()))??; - Ok(()) -} - -#[allow(dead_code)] -mod issue_2945 { - fn unit_fn() -> Result<(), i32> { - Ok(()) - } - - fn fallible() -> Result<(), i32> { - Ok(unit_fn()?) - } -} - -#[allow(dead_code)] -fn returning_expr() -> Option<()> { - foo(1); Some(()) -} - -fn taking_multiple_units(a: (), b: ()) {} - -fn main() { - bad(); - ok(); -} diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index c6e465b2e4c4b..7d1b99fedc965 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,4 +1,3 @@ -// run-rustfix #![warn(clippy::unit_arg)] #![allow(clippy::no_effect, unused_must_use, unused_variables)] @@ -36,6 +35,20 @@ fn bad() { 1; }); taking_multiple_units(foo(0), foo(1)); + taking_multiple_units(foo(0), { + foo(1); + foo(2); + }); + taking_multiple_units( + { + foo(0); + foo(1); + }, + { + foo(2); + foo(3); + }, + ); } fn ok() { diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index ce9ab2f1271a7..145b3c62b0627 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,55 +1,59 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:24:5 + --> $DIR/unit_arg.rs:23:5 | LL | foo({}); | ^^^^^^^ | = note: `-D clippy::unit-arg` implied by `-D warnings` -help: move the expressions in front of the call... +help: move the expression in front of the call... | -LL | {}; foo({}); - | ^^^ -help: ...and use unit literals instead +LL | {}; + | +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:25:5 + --> $DIR/unit_arg.rs:24:5 | LL | / foo({ LL | | 1; LL | | }); | |______^ | -help: move the expressions in front of the call... +help: remove the semicolon from the last statement in the block + | +LL | 1 + | +help: or move the expression in front of the call... | LL | { LL | 1; -LL | }; foo({ +LL | }; | -help: ...and use unit literals instead +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:28:5 + --> $DIR/unit_arg.rs:27:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expression in front of the call... | -LL | foo(1); foo(foo(1)); - | ^^^^^^^ -help: ...and use unit literals instead +LL | foo(1); + | +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:29:5 + --> $DIR/unit_arg.rs:28:5 | LL | / foo({ LL | | foo(1); @@ -57,85 +61,151 @@ LL | | foo(2); LL | | }); | |______^ | -help: move the expressions in front of the call... +help: remove the semicolon from the last statement in the block + | +LL | foo(2) + | +help: or move the expression in front of the call... | LL | { LL | foo(1); LL | foo(2); -LL | }; foo({ +LL | }; | -help: ...and use unit literals instead +help: ...and use a unit literal instead | LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:5 + --> $DIR/unit_arg.rs:32:5 | LL | foo3({}, 2, 2); | ^^^^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expression in front of the call... | -LL | {}; foo3({}, 2, 2); - | ^^^ -help: ...and use unit literals instead +LL | {}; + | +help: ...and use a unit literal instead | LL | foo3((), 2, 2); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:35:5 + --> $DIR/unit_arg.rs:34:5 | LL | / b.bar({ LL | | 1; LL | | }); | |______^ | -help: move the expressions in front of the call... +help: remove the semicolon from the last statement in the block + | +LL | 1 + | +help: or move the expression in front of the call... | LL | { LL | 1; -LL | }; b.bar({ +LL | }; | -help: ...and use unit literals instead +help: ...and use a unit literal instead | LL | b.bar(()); | ^^ -error: passing a unit value to a function - --> $DIR/unit_arg.rs:38:5 +error: passing unit values to a function + --> $DIR/unit_arg.rs:37:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: move the expressions in front of the call... | -LL | foo(0); foo(1); taking_multiple_units(foo(0), foo(1)); - | ^^^^^^^^^^^^^^^ +LL | foo(0); +LL | foo(1); + | help: ...and use unit literals instead | -LL | taking_multiple_units((), foo(1)); - | ^^ +LL | taking_multiple_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg.rs:38:5 + | +LL | / taking_multiple_units(foo(0), { +LL | | foo(1); +LL | | foo(2); +LL | | }); + | |______^ + | +help: remove the semicolon from the last statement in the block + | +LL | foo(2) + | +help: or move the expressions in front of the call... + | +LL | foo(0); +LL | { +LL | foo(1); +LL | foo(2); +LL | }; + | help: ...and use unit literals instead | -LL | taking_multiple_units(foo(0), ()); - | ^^ +LL | taking_multiple_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg.rs:42:5 + | +LL | / taking_multiple_units( +LL | | { +LL | | foo(0); +LL | | foo(1); +... | +LL | | }, +LL | | ); + | |_____^ + | +help: remove the semicolon from the last statement in the block + | +LL | foo(1) + | +help: remove the semicolon from the last statement in the block + | +LL | foo(3) + | +help: or move the expressions in front of the call... + | +LL | { +LL | foo(0); +LL | foo(1); +LL | }; +LL | { +LL | foo(2); + ... +help: ...and use unit literals instead + | +LL | (), +LL | (), + | error: passing a unit value to a function - --> $DIR/unit_arg.rs:71:5 + --> $DIR/unit_arg.rs:84:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ | -help: move the expressions in front of the call... +help: move the expression in front of the call... | -LL | foo(1); Some(foo(1)) - | ^^^^^^^ -help: ...and use unit literals instead +LL | foo(1); + | +help: ...and use a unit literal instead | LL | Some(()) | ^^ -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors From d49020573c34611b748b2d7737563f594f5c0215 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 31 May 2020 18:11:03 +0100 Subject: [PATCH 512/695] Clarify errors and warnings about the transition to the new asm! --- src/libcore/macros/mod.rs | 2 +- src/librustc_builtin_macros/asm.rs | 5 ++++- src/test/ui/asm/rustfix-asm.fixed | 4 ++-- src/test/ui/asm/rustfix-asm.rs | 4 ++-- src/test/ui/asm/rustfix-asm.stderr | 10 ++++++++-- src/test/ui/feature-gates/feature-gate-asm.rs | 2 +- src/test/ui/feature-gates/feature-gate-asm.stderr | 2 +- src/test/ui/feature-gates/feature-gate-asm2.rs | 2 +- src/test/ui/feature-gates/feature-gate-asm2.stderr | 2 +- 9 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index 625ceb0953b0a..3cfdde60135b7 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -1315,7 +1315,7 @@ pub(crate) mod builtin { #[unstable( feature = "llvm_asm", issue = "70173", - reason = "LLVM-style inline assembly will never be stabilized, prefer using asm! instead" + reason = "prefer using the new asm! syntax instead" )] #[rustc_builtin_macro] #[macro_export] diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 19fae63557289..fad638f6f2819 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -33,7 +33,10 @@ fn parse_args<'a>( // Detect use of the legacy llvm_asm! syntax (which used to be called asm!) if p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) { - let mut err = ecx.struct_span_err(sp, "legacy asm! syntax is no longer supported"); + let mut err = + ecx.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported"); + err.note("consider migrating to the new asm! syntax specified in RFC 2873"); + err.note("alternatively, switch to llvm_asm! to keep your code working as it is"); // Find the span of the "asm!" so that we can offer an automatic suggestion let asm_span = sp.from_inner(InnerSpan::new(0, 4)); diff --git a/src/test/ui/asm/rustfix-asm.fixed b/src/test/ui/asm/rustfix-asm.fixed index c9271059810c7..01d8fd34b68a8 100644 --- a/src/test/ui/asm/rustfix-asm.fixed +++ b/src/test/ui/asm/rustfix-asm.fixed @@ -8,9 +8,9 @@ fn main() { let x = 1; let y: i32; llvm_asm!("" :: "r" (x)); - //~^ ERROR legacy asm! syntax is no longer supported + //~^ ERROR the legacy LLVM-style asm! syntax is no longer supported llvm_asm!("" : "=r" (y)); - //~^ ERROR legacy asm! syntax is no longer supported + //~^ ERROR the legacy LLVM-style asm! syntax is no longer supported let _ = y; } } diff --git a/src/test/ui/asm/rustfix-asm.rs b/src/test/ui/asm/rustfix-asm.rs index a108595ca1b66..e25895b723049 100644 --- a/src/test/ui/asm/rustfix-asm.rs +++ b/src/test/ui/asm/rustfix-asm.rs @@ -8,9 +8,9 @@ fn main() { let x = 1; let y: i32; asm!("" :: "r" (x)); - //~^ ERROR legacy asm! syntax is no longer supported + //~^ ERROR the legacy LLVM-style asm! syntax is no longer supported asm!("" : "=r" (y)); - //~^ ERROR legacy asm! syntax is no longer supported + //~^ ERROR the legacy LLVM-style asm! syntax is no longer supported let _ = y; } } diff --git a/src/test/ui/asm/rustfix-asm.stderr b/src/test/ui/asm/rustfix-asm.stderr index 28675b51d15fb..334499c6fd897 100644 --- a/src/test/ui/asm/rustfix-asm.stderr +++ b/src/test/ui/asm/rustfix-asm.stderr @@ -1,18 +1,24 @@ -error: legacy asm! syntax is no longer supported +error: the legacy LLVM-style asm! syntax is no longer supported --> $DIR/rustfix-asm.rs:10:9 | LL | asm!("" :: "r" (x)); | ----^^^^^^^^^^^^^^^^ | | | help: replace with: `llvm_asm!` + | + = note: consider migrating to the new asm! syntax specified in RFC 2873 + = note: alternatively, switch to llvm_asm! to keep your code working as it is -error: legacy asm! syntax is no longer supported +error: the legacy LLVM-style asm! syntax is no longer supported --> $DIR/rustfix-asm.rs:12:9 | LL | asm!("" : "=r" (y)); | ----^^^^^^^^^^^^^^^^ | | | help: replace with: `llvm_asm!` + | + = note: consider migrating to the new asm! syntax specified in RFC 2873 + = note: alternatively, switch to llvm_asm! to keep your code working as it is error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-asm.rs b/src/test/ui/feature-gates/feature-gate-asm.rs index 4eb72031d51b1..753e924f00495 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.rs +++ b/src/test/ui/feature-gates/feature-gate-asm.rs @@ -5,6 +5,6 @@ fn main() { asm!(""); //~^ ERROR inline assembly is not stable enough llvm_asm!(""); - //~^ ERROR LLVM-style inline assembly will never be stabilized + //~^ ERROR prefer using the new asm! syntax instead } } diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr index a71643e0d33a3..d770565b0991c 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm.stderr @@ -7,7 +7,7 @@ LL | asm!(""); = note: see issue #72016 for more information = help: add `#![feature(asm)]` to the crate attributes to enable -error[E0658]: use of unstable library feature 'llvm_asm': LLVM-style inline assembly will never be stabilized, prefer using asm! instead +error[E0658]: use of unstable library feature 'llvm_asm': prefer using the new asm! syntax instead --> $DIR/feature-gate-asm.rs:7:9 | LL | llvm_asm!(""); diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs index 8bd7226aca730..e9349acb64394 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.rs +++ b/src/test/ui/feature-gates/feature-gate-asm2.rs @@ -5,6 +5,6 @@ fn main() { println!("{:?}", asm!("")); //~^ ERROR inline assembly is not stable enough println!("{:?}", llvm_asm!("")); - //~^ ERROR LLVM-style inline assembly will never be stabilized + //~^ ERROR prefer using the new asm! syntax instead } } diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr index a8022cb72e0e3..85278c98d77e9 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr @@ -7,7 +7,7 @@ LL | println!("{:?}", asm!("")); = note: see issue #72016 for more information = help: add `#![feature(asm)]` to the crate attributes to enable -error[E0658]: use of unstable library feature 'llvm_asm': LLVM-style inline assembly will never be stabilized, prefer using asm! instead +error[E0658]: use of unstable library feature 'llvm_asm': prefer using the new asm! syntax instead --> $DIR/feature-gate-asm2.rs:7:26 | LL | println!("{:?}", llvm_asm!("")); From a9cde3a804808e82402888a20878053404a8eded Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 31 May 2020 18:45:16 +0200 Subject: [PATCH 513/695] Don't suggest to move empty blocks --- clippy_lints/src/types.rs | 43 +++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 6866635b904be..5ca30d598eb15 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -10,7 +10,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ - BinOpKind, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, + BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TyKind, UnOp, }; @@ -29,10 +29,10 @@ use rustc_typeck::hir_ty_to_ty; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, in_constant, int_bits, is_type_diagnostic_item, + clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, - qpath_res, same_tys, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, - span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, + qpath_res, same_tys, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; declare_clippy_lint! { @@ -847,6 +847,7 @@ fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[ }); let sugg = args_to_recover .iter() + .filter(|arg| !is_empty_block(arg)) .enumerate() .map(|(i, arg)| { let indent = if i == 0 { @@ -860,16 +861,20 @@ fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[ snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability) ) }) - .collect::>() - .join("\n"); - db.span_suggestion( - expr.span.with_hi(expr.span.lo()), - &format!("{}move the expression{} in front of the call...", or, plural), - format!("{}\n", sugg), - applicability, - ); + .collect::>(); + let mut and = ""; + if !sugg.is_empty() { + let plural = if sugg.len() > 1 { "s" } else { "" }; + db.span_suggestion( + expr.span.with_hi(expr.span.lo()), + &format!("{}move the expression{} in front of the call...", or, plural), + format!("{}\n", sugg.join("\n")), + applicability, + ); + and = "...and " + } db.multipart_suggestion( - &format!("...and use {}unit literal{} instead", singular, plural), + &format!("{}use {}unit literal{} instead", and, singular, plural), args_to_recover .iter() .map(|arg| (arg.span, "()".to_string())) @@ -880,6 +885,18 @@ fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[ ); } +fn is_empty_block(expr: &Expr<'_>) -> bool { + matches!( + expr.kind, + ExprKind::Block( + Block { + stmts: &[], expr: None, .. + }, + _, + ) + ) +} + fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::DesugaringKind; if let ExprKind::Call(ref callee, _) = expr.kind { From 77dd0ea62aa6a2af70da4c5e05de064eee182a6c Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 31 May 2020 19:29:36 +0200 Subject: [PATCH 514/695] Add tests for empty blocks --- tests/ui/unit_arg.rs | 2 -- tests/ui/unit_arg.stderr | 46 +++++------------------- tests/ui/unit_arg_empty_blocks.rs | 26 ++++++++++++++ tests/ui/unit_arg_empty_blocks.stderr | 51 +++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 40 deletions(-) create mode 100644 tests/ui/unit_arg_empty_blocks.rs create mode 100644 tests/ui/unit_arg_empty_blocks.stderr diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 7d1b99fedc965..2992abae775b8 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -20,7 +20,6 @@ impl Bar { } fn bad() { - foo({}); foo({ 1; }); @@ -29,7 +28,6 @@ fn bad() { foo(1); foo(2); }); - foo3({}, 2, 2); let b = Bar; b.bar({ 1; diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 145b3c62b0627..56f6a855dfa55 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,27 +1,12 @@ error: passing a unit value to a function --> $DIR/unit_arg.rs:23:5 | -LL | foo({}); - | ^^^^^^^ - | - = note: `-D clippy::unit-arg` implied by `-D warnings` -help: move the expression in front of the call... - | -LL | {}; - | -help: ...and use a unit literal instead - | -LL | foo(()); - | ^^ - -error: passing a unit value to a function - --> $DIR/unit_arg.rs:24:5 - | LL | / foo({ LL | | 1; LL | | }); | |______^ | + = note: `-D clippy::unit-arg` implied by `-D warnings` help: remove the semicolon from the last statement in the block | LL | 1 @@ -38,7 +23,7 @@ LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:27:5 + --> $DIR/unit_arg.rs:26:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -53,7 +38,7 @@ LL | foo(()); | ^^ error: passing a unit value to a function - --> $DIR/unit_arg.rs:28:5 + --> $DIR/unit_arg.rs:27:5 | LL | / foo({ LL | | foo(1); @@ -80,21 +65,6 @@ LL | foo(()); error: passing a unit value to a function --> $DIR/unit_arg.rs:32:5 | -LL | foo3({}, 2, 2); - | ^^^^^^^^^^^^^^ - | -help: move the expression in front of the call... - | -LL | {}; - | -help: ...and use a unit literal instead - | -LL | foo3((), 2, 2); - | ^^ - -error: passing a unit value to a function - --> $DIR/unit_arg.rs:34:5 - | LL | / b.bar({ LL | | 1; LL | | }); @@ -116,7 +86,7 @@ LL | b.bar(()); | ^^ error: passing unit values to a function - --> $DIR/unit_arg.rs:37:5 + --> $DIR/unit_arg.rs:35:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +102,7 @@ LL | taking_multiple_units((), ()); | ^^ ^^ error: passing unit values to a function - --> $DIR/unit_arg.rs:38:5 + --> $DIR/unit_arg.rs:36:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -158,7 +128,7 @@ LL | taking_multiple_units((), ()); | ^^ ^^ error: passing unit values to a function - --> $DIR/unit_arg.rs:42:5 + --> $DIR/unit_arg.rs:40:5 | LL | / taking_multiple_units( LL | | { @@ -193,7 +163,7 @@ LL | (), | error: passing a unit value to a function - --> $DIR/unit_arg.rs:84:5 + --> $DIR/unit_arg.rs:82:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ @@ -207,5 +177,5 @@ help: ...and use a unit literal instead LL | Some(()) | ^^ -error: aborting due to 10 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/unit_arg_empty_blocks.rs b/tests/ui/unit_arg_empty_blocks.rs new file mode 100644 index 0000000000000..18a31eb3deee2 --- /dev/null +++ b/tests/ui/unit_arg_empty_blocks.rs @@ -0,0 +1,26 @@ +#![warn(clippy::unit_arg)] +#![allow(clippy::no_effect, unused_must_use, unused_variables)] + +use std::fmt::Debug; + +fn foo(t: T) { + println!("{:?}", t); +} + +fn foo3(t1: T1, t2: T2, t3: T3) { + println!("{:?}, {:?}, {:?}", t1, t2, t3); +} + +fn bad() { + foo({}); + foo3({}, 2, 2); + taking_two_units({}, foo(0)); + taking_three_units({}, foo(0), foo(1)); +} + +fn taking_two_units(a: (), b: ()) {} +fn taking_three_units(a: (), b: (), c: ()) {} + +fn main() { + bad(); +} diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr new file mode 100644 index 0000000000000..bb58483584b3e --- /dev/null +++ b/tests/ui/unit_arg_empty_blocks.stderr @@ -0,0 +1,51 @@ +error: passing a unit value to a function + --> $DIR/unit_arg_empty_blocks.rs:15:5 + | +LL | foo({}); + | ^^^^--^ + | | + | help: use a unit literal instead: `()` + | + = note: `-D clippy::unit-arg` implied by `-D warnings` + +error: passing a unit value to a function + --> $DIR/unit_arg_empty_blocks.rs:16:5 + | +LL | foo3({}, 2, 2); + | ^^^^^--^^^^^^^ + | | + | help: use a unit literal instead: `()` + +error: passing unit values to a function + --> $DIR/unit_arg_empty_blocks.rs:17:5 + | +LL | taking_two_units({}, foo(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call... + | +LL | foo(0); + | +help: ...and use unit literals instead + | +LL | taking_two_units((), ()); + | ^^ ^^ + +error: passing unit values to a function + --> $DIR/unit_arg_empty_blocks.rs:18:5 + | +LL | taking_three_units({}, foo(0), foo(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call... + | +LL | foo(0); +LL | foo(1); + | +help: ...and use unit literals instead + | +LL | taking_three_units((), (), ()); + | ^^ ^^ ^^ + +error: aborting due to 4 previous errors + From 186b274fd934ab4a7b2211954046d58164781f9e Mon Sep 17 00:00:00 2001 From: Miller Date: Mon, 1 Jun 2020 00:15:35 +0600 Subject: [PATCH 515/695] changed *nix to Unix-like --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00bb501941dd7..b48ee8a914ec4 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ or reading the [rustc dev guide][rustcguidebuild]. [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html -### Building on *nix +### Building on Unix-like system 1. Make sure you have installed the dependencies: * `g++` 5.1 or later or `clang++` 3.5 or later From dd0338fbac143cb0c3844575f5ae4406854b56c5 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 31 May 2020 14:37:26 -0400 Subject: [PATCH 516/695] Clarify terms in doc comments Doc comments of 'copy_from_slice' say that people should use 'clone_from_slice' when 'src' doesn't implement 'Copy'. However, 'src' is a reference and it always implements 'Copy'. The term 'src' should be fixed to 'T' in the doc comments. Thank you for reviewing this PR :) --- src/libcore/slice/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 2361749f16645..ff333f77334f7 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2173,7 +2173,7 @@ impl [T] { /// /// The length of `src` must be the same as `self`. /// - /// If `src` implements `Copy`, it can be more performant to use + /// If `T` implements `Copy`, it can be more performant to use /// [`copy_from_slice`]. /// /// # Panics @@ -2244,7 +2244,7 @@ impl [T] { /// /// The length of `src` must be the same as `self`. /// - /// If `src` does not implement `Copy`, use [`clone_from_slice`]. + /// If `T` does not implement `Copy`, use [`clone_from_slice`]. /// /// # Panics /// From 14e9100543166e48acd0ea00233249d2cddf09c2 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Mon, 25 May 2020 00:41:13 +0200 Subject: [PATCH 517/695] cargo-ui tests: check that