From 6fd5cf51c1528c16f8a186ced5d6d21b1d70e319 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Wed, 13 Oct 2021 08:46:34 -0700 Subject: [PATCH 01/10] Add documentation to more `From::from` implementations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For users looking at documentation through IDE popups, this gives them relevant information rather than the generic trait documentation wording “Performs the conversion”. For users reading the documentation for a specific type for any reason, this informs them when the conversion may allocate or copy significant memory versus when it is always a move or cheap copy. Notes on specific cases: * The new documentation for `From for T` explains that it is not a conversion at all. * Also documented `impl Into for T where U: From`, the other central blanket implementation of conversion. * I did not add documentation to conversions of a specific error type to a more general error type. * I did not add documentation to unstable code. This change was prepared by searching for the text "From<... for" and so may have missed some cases that for whatever reason did not match. I also looked for `Into` impls but did not find any worth documenting by the above criteria. --- library/alloc/src/collections/btree/map.rs | 2 ++ library/alloc/src/collections/btree/set.rs | 2 ++ library/alloc/src/collections/linked_list.rs | 2 ++ library/alloc/src/collections/vec_deque/mod.rs | 2 ++ library/alloc/src/vec/mod.rs | 9 +++++---- library/core/src/cell.rs | 3 +++ library/core/src/convert/mod.rs | 5 +++++ library/core/src/lazy.rs | 1 + library/core/src/ptr/non_null.rs | 6 ++++++ library/core/src/ptr/unique.rs | 3 +++ library/core/src/sync/atomic.rs | 1 + library/core/src/task/poll.rs | 2 +- library/std/src/ffi/c_str.rs | 11 +++++++++++ library/std/src/ffi/os_str.rs | 12 ++++++++++++ library/std/src/path.rs | 6 +++--- library/std/src/process.rs | 8 ++++---- 16 files changed, 63 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 2ff7b0fbb759c..f015e081ea3de 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2047,6 +2047,8 @@ where #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl From<[(K, V); N]> for BTreeMap { + /// Converts a `[(K, V); N]` into a `BTreeMap<(K, V)>`. + /// /// ``` /// use std::collections::BTreeMap; /// diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 0322cabccde4b..ec4ed85437287 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1092,6 +1092,8 @@ impl FromIterator for BTreeSet { #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl From<[T; N]> for BTreeSet { + /// Converts a `[T; N]` into a `BTreeSet`. + /// /// ``` /// use std::collections::BTreeSet; /// diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index e4913b16adbe7..30b07c0aebe01 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1953,6 +1953,8 @@ impl Hash for LinkedList { #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl From<[T; N]> for LinkedList { + /// Converts a `[T; N]` into a `LinkedList`. + /// /// ``` /// use std::collections::LinkedList; /// diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 00862615c3c7a..061e2758e4985 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -3018,6 +3018,8 @@ impl From> for Vec { #[stable(feature = "std_collections_from_array", since = "1.56.0")] impl From<[T; N]> for VecDeque { + /// Converts a `[T; N]` into a `VecDeque`. + /// /// ``` /// use std::collections::VecDeque; /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 88bde6e8ce481..0cc4a55dc99c9 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2908,10 +2908,6 @@ impl From<&mut [T]> for Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_from_array", since = "1.44.0")] impl From<[T; N]> for Vec { - #[cfg(not(test))] - fn from(s: [T; N]) -> Vec { - <[T]>::into_vec(box s) - } /// Allocate a `Vec` and move `s`'s items into it. /// /// # Examples @@ -2919,6 +2915,11 @@ impl From<[T; N]> for Vec { /// ``` /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); /// ``` + #[cfg(not(test))] + fn from(s: [T; N]) -> Vec { + <[T]>::into_vec(box s) + } + #[cfg(test)] fn from(s: [T; N]) -> Vec { crate::slice::into_vec(box s) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 06dc5ecf2ffa6..235e43a3048d8 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -315,6 +315,7 @@ impl Ord for Cell { #[stable(feature = "cell_from", since = "1.12.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for Cell { + /// Creates a new `Cell` containing the given value. fn from(t: T) -> Cell { Cell::new(t) } @@ -1244,6 +1245,7 @@ impl Ord for RefCell { #[stable(feature = "cell_from", since = "1.12.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for RefCell { + /// Creates a new `RefCell` containing the given value. fn from(t: T) -> RefCell { RefCell::new(t) } @@ -1986,6 +1988,7 @@ impl Default for UnsafeCell { #[stable(feature = "cell_from", since = "1.12.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for UnsafeCell { + /// Creates a new `UnsafeCell` containing the given value. fn from(t: T) -> UnsafeCell { UnsafeCell::new(t) } diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 5aa53deee343d..de23dda1d0f4d 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -538,6 +538,10 @@ impl Into for T where U: From, { + /// Calls `U::from(self)`. + /// + /// That is, this conversion is whatever the implementation of + /// [From]<T> for U chooses to do. fn into(self) -> U { U::from(self) } @@ -547,6 +551,7 @@ where #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for T { + /// Returns the argument unchanged. fn from(t: T) -> T { t } diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs index 2b8a5f3cbf345..6e08a7d24c6b0 100644 --- a/library/core/src/lazy.rs +++ b/library/core/src/lazy.rs @@ -75,6 +75,7 @@ impl Eq for OnceCell {} #[unstable(feature = "once_cell", issue = "74465")] impl const From for OnceCell { + /// Creates a new `OnceCell` which already contains the given `value`. fn from(value: T) -> Self { OnceCell { inner: UnsafeCell::new(Some(value)) } } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 58110b0680943..84ffd8bc8e204 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -714,6 +714,9 @@ impl const From> for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From<&mut T> for NonNull { + /// Converts a `&mut T` to a `NonNull`. + /// + /// This conversion is safe and infallible since references cannot be null. #[inline] fn from(reference: &mut T) -> Self { // SAFETY: A mutable reference cannot be null. @@ -724,6 +727,9 @@ impl const From<&mut T> for NonNull { #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From<&T> for NonNull { + /// Converts a `&T` to a `NonNull`. + /// + /// This conversion is safe and infallible since references cannot be null. #[inline] fn from(reference: &T) -> Self { // SAFETY: A reference cannot be null, so the conditions for diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index d650a6f974b97..f88d4b72fcf6b 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -178,6 +178,9 @@ impl fmt::Pointer for Unique { #[unstable(feature = "ptr_internals", issue = "none")] impl const From<&mut T> for Unique { + /// Converts a `&mut T` to a `Unique`. + /// + /// This conversion is infallible since references cannot be null. #[inline] fn from(reference: &mut T) -> Self { // SAFETY: A mutable reference cannot be null diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 1dd3b2d8e3c8d..93cdab59e4429 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1294,6 +1294,7 @@ impl const From for AtomicBool { #[stable(feature = "atomic_from", since = "1.23.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From<*mut T> for AtomicPtr { + /// Converts a `*mut T` into an `AtomicPtr`. #[inline] fn from(p: *mut T) -> Self { Self::new(p) diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 72a030617ad8a..41f0a25dbc3e0 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -243,7 +243,7 @@ impl Poll>> { #[stable(feature = "futures_api", since = "1.36.0")] #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for Poll { - /// Convert to a `Ready` variant. + /// Moves the value into a [`Poll::Ready`] to make a `Poll`. /// /// # Example /// diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 465bbae8631c5..62b6eefbe1866 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -848,6 +848,8 @@ impl Borrow for CString { #[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")] impl<'a> From> for CString { + /// Converts a `Cow<'a, CStr>` into a `CString`, by copying the contents if they are + /// borrowed. #[inline] fn from(s: Cow<'a, CStr>) -> Self { s.into_owned() @@ -856,6 +858,8 @@ impl<'a> From> for CString { #[stable(feature = "box_from_c_str", since = "1.17.0")] impl From<&CStr> for Box { + /// Converts a `&CStr` into a `Box`, + /// by copying the contents into a newly allocated [`Box`]. fn from(s: &CStr) -> Box { let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } @@ -864,6 +868,8 @@ impl From<&CStr> for Box { #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { + /// Converts a `Cow<'a, CStr>` into a `Box`, + /// by copying the contents if they are borrowed. #[inline] fn from(cow: Cow<'_, CStr>) -> Box { match cow { @@ -960,6 +966,8 @@ impl From for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&CStr> for Arc { + /// Converts a `&CStr` into a `Arc`, + /// by copying the contents into a newly allocated [`Arc`]. #[inline] fn from(s: &CStr) -> Arc { let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul()); @@ -979,6 +987,8 @@ impl From for Rc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&CStr> for Rc { + /// Converts a `&CStr` into a `Rc`, + /// by copying the contents into a newly allocated [`Rc`]. #[inline] fn from(s: &CStr) -> Rc { let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul()); @@ -1504,6 +1514,7 @@ impl ToOwned for CStr { #[stable(feature = "cstring_asref", since = "1.7.0")] impl From<&CStr> for CString { + /// Copies the contents of the `&CStr` into a newly allocated `CString`. fn from(s: &CStr) -> CString { s.to_owned() } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 0f9912fa64d8b..7bb2ff6770ec5 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -371,6 +371,8 @@ impl From for OsString { #[stable(feature = "rust1", since = "1.0.0")] impl> From<&T> for OsString { + /// Copies any value implementing [AsRef]<[OsStr]> + /// into a newly allocated [`OsString`]. fn from(s: &T) -> OsString { s.as_ref().to_os_string() } @@ -861,6 +863,7 @@ impl OsStr { #[stable(feature = "box_from_os_str", since = "1.17.0")] impl From<&OsStr> for Box { + /// Copies the string into a newly allocated [Box]<[OsStr]>. #[inline] fn from(s: &OsStr) -> Box { let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr; @@ -870,6 +873,8 @@ impl From<&OsStr> for Box { #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { + /// Converts a `Cow<'a, OsStr>` into a [Box]<[OsStr]>, + /// by copying the contents if they are borrowed. #[inline] fn from(cow: Cow<'_, OsStr>) -> Box { match cow { @@ -918,6 +923,7 @@ impl From for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&OsStr> for Arc { + /// Copies the string into a newly allocated [Arc]<[OsStr]>. #[inline] fn from(s: &OsStr) -> Arc { let arc = s.inner.into_arc(); @@ -937,6 +943,7 @@ impl From for Rc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&OsStr> for Rc { + /// Copies the string into a newly allocated [Rc]<[OsStr]>. #[inline] fn from(s: &OsStr) -> Rc { let rc = s.inner.into_rc(); @@ -946,6 +953,7 @@ impl From<&OsStr> for Rc { #[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From for Cow<'a, OsStr> { + /// Moves the string into a [`Cow::Owned`]. #[inline] fn from(s: OsString) -> Cow<'a, OsStr> { Cow::Owned(s) @@ -954,6 +962,7 @@ impl<'a> From for Cow<'a, OsStr> { #[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { + /// Converts the string reference into a [`Cow::Borrowed`]. #[inline] fn from(s: &'a OsStr) -> Cow<'a, OsStr> { Cow::Borrowed(s) @@ -962,6 +971,7 @@ impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { #[stable(feature = "cow_from_osstr", since = "1.28.0")] impl<'a> From<&'a OsString> for Cow<'a, OsStr> { + /// Converts the string reference into a [`Cow::Borrowed`]. #[inline] fn from(s: &'a OsString) -> Cow<'a, OsStr> { Cow::Borrowed(s.as_os_str()) @@ -970,6 +980,8 @@ impl<'a> From<&'a OsString> for Cow<'a, OsStr> { #[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")] impl<'a> From> for OsString { + /// Converts a `Cow<'a, OsStr>` into an [`OsString`], + /// by copying the contents if they are borrowed. #[inline] fn from(s: Cow<'a, OsStr>) -> Self { s.into_owned() diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9ade2847e8ea9..a4d0119c2a063 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1581,7 +1581,7 @@ impl From> for Box { #[stable(feature = "path_buf_from_box", since = "1.18.0")] impl From> for PathBuf { - /// Converts a `Box` into a `PathBuf` + /// Converts a [Box]<[Path]> into a [`PathBuf`]. /// /// This conversion does not allocate or copy memory. #[inline] @@ -1592,7 +1592,7 @@ impl From> for PathBuf { #[stable(feature = "box_from_path_buf", since = "1.20.0")] impl From for Box { - /// Converts a `PathBuf` into a `Box` + /// Converts a [`PathBuf`] into a [Box]<[Path]>. /// /// This conversion currently should not allocate memory, /// but this behavior is not guaranteed on all platforms or in all future versions. @@ -1612,7 +1612,7 @@ impl Clone for Box { #[stable(feature = "rust1", since = "1.0.0")] impl> From<&T> for PathBuf { - /// Converts a borrowed `OsStr` to a `PathBuf`. + /// Converts a borrowed [`OsStr`] to a [`PathBuf`]. /// /// Allocates a [`PathBuf`] and copies the data into it. #[inline] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 4e9fd51f28229..ae39997de6212 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1289,7 +1289,7 @@ impl fmt::Debug for Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From for Stdio { - /// Converts a `ChildStdin` into a `Stdio` + /// Converts a [`ChildStdin`] into a [`Stdio`]. /// /// # Examples /// @@ -1318,7 +1318,7 @@ impl From for Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From for Stdio { - /// Converts a `ChildStdout` into a `Stdio` + /// Converts a [`ChildStdout`] into a [`Stdio`]. /// /// # Examples /// @@ -1347,7 +1347,7 @@ impl From for Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From for Stdio { - /// Converts a `ChildStderr` into a `Stdio` + /// Converts a [`ChildStderr`] into a [`Stdio`]. /// /// # Examples /// @@ -1378,7 +1378,7 @@ impl From for Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From for Stdio { - /// Converts a `File` into a `Stdio` + /// Converts a [`File`](fs::File) into a [`Stdio`]. /// /// # Examples /// From 96d96a7ac48cd8becf3133035ab0cf0717a4cf75 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sun, 30 Jan 2022 10:25:40 -0500 Subject: [PATCH 02/10] Use `optflag` for `--report-time` Essentially, what is described here: https://github.com/rust-lang/rust/issues/64888#issuecomment-1008047228 There is one difference. The comment proposes to add a `--report-time-color` option. This change instead uses libtest's existing `--color` option for that purpose. --- library/test/src/cli.rs | 14 +++----------- library/test/src/formatters/pretty.rs | 2 +- library/test/src/tests.rs | 1 - library/test/src/time.rs | 5 ++--- src/doc/rustc/src/tests/index.md | 2 +- .../src/compiler-flags/report-time.md | 7 ++----- 6 files changed, 9 insertions(+), 22 deletions(-) diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index cb40b4e965b2a..b39701a3d4288 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -109,12 +109,10 @@ fn optgroups() -> getopts::Options { unstable-options = Allow use of experimental features", "unstable-options", ) - .optflagopt( + .optflag( "", "report-time", - "Show execution time of each test. Available values: - plain = do not colorize the execution time (default); - colored = colorize output according to the `color` parameter value; + "Show execution time of each test. Threshold values for colorized output can be configured via `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and @@ -125,7 +123,6 @@ fn optgroups() -> getopts::Options { is 0.5 seconds, and the critical time is 2 seconds. Not available for --format=terse", - "plain|colored", ) .optflag( "", @@ -319,17 +316,12 @@ fn get_time_options( allow_unstable: bool, ) -> OptPartRes> { let report_time = unstable_optflag!(matches, allow_unstable, "report-time"); - let colored_opt_str = matches.opt_str("report-time"); - let mut report_time_colored = report_time && colored_opt_str == Some("colored".into()); let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time"); // If `ensure-test-time` option is provided, time output is enforced, // so user won't be confused if any of tests will silently fail. let options = if report_time || ensure_test_time { - if ensure_test_time && !report_time { - report_time_colored = true; - } - Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored)) + Some(TestTimeOptions::new_from_env(ensure_test_time)) } else { None }; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 4a03b4b914760..5da275d4af718 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -102,7 +102,7 @@ impl PrettyFormatter { if let (Some(opts), Some(time)) = (self.time_options, exec_time) { let time_str = format!(" <{}>", time); - let color = if opts.colored { + let color = if self.use_color { if opts.is_critical(desc, time) { Some(term::color::RED) } else if opts.is_warn(desc, time) { diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 7f0b6193d09ac..f563d490d1175 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -382,7 +382,6 @@ fn test_time_options_threshold() { let options = TestTimeOptions { error_on_excess: false, - colored: false, unit_threshold: unit.clone(), integration_threshold: integration.clone(), doctest_threshold: doc.clone(), diff --git a/library/test/src/time.rs b/library/test/src/time.rs index e0b6eadffa119..8c64e5d1b7339 100644 --- a/library/test/src/time.rs +++ b/library/test/src/time.rs @@ -137,14 +137,13 @@ pub struct TestTimeOptions { /// Denotes if the test critical execution time limit excess should be considered /// a test failure. pub error_on_excess: bool, - pub colored: bool, pub unit_threshold: TimeThreshold, pub integration_threshold: TimeThreshold, pub doctest_threshold: TimeThreshold, } impl TestTimeOptions { - pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self { + pub fn new_from_env(error_on_excess: bool) -> Self { let unit_threshold = TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME) .unwrap_or_else(Self::default_unit); @@ -155,7 +154,7 @@ impl TestTimeOptions { let doctest_threshold = TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME) .unwrap_or_else(Self::default_doctest); - Self { error_on_excess, colored, unit_threshold, integration_threshold, doctest_threshold } + Self { error_on_excess, unit_threshold, integration_threshold, doctest_threshold } } pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool { diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md index 23a9f31e8e7da..0e0eb85db746a 100644 --- a/src/doc/rustc/src/tests/index.md +++ b/src/doc/rustc/src/tests/index.md @@ -267,7 +267,7 @@ Controls the format of the output. Valid options: Writes the results of the tests to the given file. -#### `--report-time` _FORMAT_ +#### `--report-time` ⚠️ 🚧 This option is [unstable](#unstable-options), and requires the `-Z unstable-options` flag. See [tracking issue diff --git a/src/doc/unstable-book/src/compiler-flags/report-time.md b/src/doc/unstable-book/src/compiler-flags/report-time.md index ac0093f77aec2..9e6a1fb000575 100644 --- a/src/doc/unstable-book/src/compiler-flags/report-time.md +++ b/src/doc/unstable-book/src/compiler-flags/report-time.md @@ -21,11 +21,8 @@ Sample usage command: Available options: ```sh ---report-time [plain|colored] - Show execution time of each test. Available values: - plain = do not colorize the execution time (default); - colored = colorize output according to the `color` - parameter value; +--report-time + Show execution time of each test. Threshold values for colorized output can be configured via `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` From d9592d90c707ff1badb8067eb0a0e252d241ee9e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 14 Feb 2022 00:00:07 +0000 Subject: [PATCH 03/10] Fix suggestion to slice if scurtinee is a reference to `Result` or `Option` --- compiler/rustc_typeck/src/check/pat.rs | 56 +++++++++++++++----------- src/test/ui/typeck/issue-91328.fixed | 10 +++++ src/test/ui/typeck/issue-91328.rs | 10 +++++ src/test/ui/typeck/issue-91328.stderr | 11 ++++- 4 files changed, 62 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 62cd9c64a4a7c..af378a0e708a2 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -2029,34 +2029,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.help("the semantics of slice patterns changed recently; see issue #62254"); } } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span) - .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..))) + .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) { if let (Some(span), true) = (ti.span, ti.origin_expr) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let applicability = match self.resolve_vars_if_possible(ti.expected).kind() { - ty::Adt(adt_def, _) - if self.tcx.is_diagnostic_item(sym::Option, adt_def.did) - || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) => - { - // Slicing won't work here, but `.as_deref()` might (issue #91328). - err.span_suggestion( - span, - "consider using `as_deref` here", - format!("{}.as_deref()", snippet), - Applicability::MaybeIncorrect, - ); - None - } - // FIXME: instead of checking for Vec only, we could check whether the - // type implements `Deref`; see - // https://github.com/rust-lang/rust/pull/91343#discussion_r761466979 - ty::Adt(adt_def, _) - if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did) => - { - Some(Applicability::MachineApplicable) + let applicability = Autoderef::new( + &self.infcx, + self.param_env, + self.body_id, + span, + self.resolve_vars_if_possible(ti.expected), + span, + ) + .find_map(|(ty, _)| { + match ty.kind() { + ty::Adt(adt_def, _) + if self.tcx.is_diagnostic_item(sym::Option, adt_def.did) + || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) => + { + // Slicing won't work here, but `.as_deref()` might (issue #91328). + err.span_suggestion( + span, + "consider using `as_deref` here", + format!("{}.as_deref()", snippet), + Applicability::MaybeIncorrect, + ); + Some(None) + } + + ty::Slice(..) | ty::Array(..) => { + Some(Some(Applicability::MachineApplicable)) + } + + _ => None, } - _ => Some(Applicability::MaybeIncorrect), - }; + }) + .unwrap_or(Some(Applicability::MaybeIncorrect)); if let Some(applicability) = applicability { err.span_suggestion( diff --git a/src/test/ui/typeck/issue-91328.fixed b/src/test/ui/typeck/issue-91328.fixed index 81b6a99607215..c0384399a92e6 100644 --- a/src/test/ui/typeck/issue-91328.fixed +++ b/src/test/ui/typeck/issue-91328.fixed @@ -34,4 +34,14 @@ fn baz(v: Vec) -> i32 { } } +fn qux(a: &Option>) -> i32 { + match a.as_deref() { + //~^ HELP: consider using `as_deref` here + Some([a, b]) => a + b, + //~^ ERROR: expected an array or slice + //~| NOTE: pattern cannot match with input type + _ => 42, + } +} + fn main() {} diff --git a/src/test/ui/typeck/issue-91328.rs b/src/test/ui/typeck/issue-91328.rs index e938d8f5c9f04..63602d26f970d 100644 --- a/src/test/ui/typeck/issue-91328.rs +++ b/src/test/ui/typeck/issue-91328.rs @@ -34,4 +34,14 @@ fn baz(v: Vec) -> i32 { } } +fn qux(a: &Option>) -> i32 { + match a { + //~^ HELP: consider using `as_deref` here + Some([a, b]) => a + b, + //~^ ERROR: expected an array or slice + //~| NOTE: pattern cannot match with input type + _ => 42, + } +} + fn main() {} diff --git a/src/test/ui/typeck/issue-91328.stderr b/src/test/ui/typeck/issue-91328.stderr index 96ad00cde4f7b..f2f407bcafff2 100644 --- a/src/test/ui/typeck/issue-91328.stderr +++ b/src/test/ui/typeck/issue-91328.stderr @@ -25,6 +25,15 @@ LL | LL | [a, b] => a + b, | ^^^^^^ pattern cannot match with input type `Vec` -error: aborting due to 3 previous errors +error[E0529]: expected an array or slice, found `Box<[i32; 2]>` + --> $DIR/issue-91328.rs:40:14 + | +LL | match a { + | - help: consider using `as_deref` here: `a.as_deref()` +LL | +LL | Some([a, b]) => a + b, + | ^^^^^^ pattern cannot match with input type `Box<[i32; 2]>` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0529`. From 8610edd01451e16d4fcb66324a27890c559fbf7b Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Sun, 6 Feb 2022 17:44:41 +1100 Subject: [PATCH 04/10] Suggest deriving required supertraits --- .../rustc_typeck/src/check/method/suggest.rs | 17 +++- src/test/ui/derives/issue-91550.rs | 29 +++++++ src/test/ui/derives/issue-91550.stderr | 84 +++++++++++++++++++ 3 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/derives/issue-91550.rs create mode 100644 src/test/ui/derives/issue-91550.stderr diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 81e2b3bc1621f..5b06cc333027e 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1196,7 +1196,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(adt) if adt.did.is_local() => adt, _ => continue, }; - let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) { + let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id()); + let can_derive = match diagnostic_name { Some(sym::Default) => !adt.is_enum(), Some( sym::Eq @@ -1211,10 +1212,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => false, }; if can_derive { + let self_name = trait_pred.self_ty().to_string(); + let self_span = self.tcx.def_span(adt.did); + if let Some(sym::Ord) = diagnostic_name { + derives.push((self_name.clone(), self_span.clone(), "PartialOrd".to_string())); + } + if let Some(sym::Eq) = diagnostic_name { + derives.push((self_name.clone(), self_span.clone(), "PartialEq".to_string())); + } derives.push(( - format!("{}", trait_pred.self_ty()), - self.tcx.def_span(adt.did), - format!("{}", trait_pred.trait_ref.print_only_trait_name()), + self_name, + self_span, + trait_pred.trait_ref.print_only_trait_name().to_string(), )); } else { traits.push(self.tcx.def_span(trait_pred.def_id())); diff --git a/src/test/ui/derives/issue-91550.rs b/src/test/ui/derives/issue-91550.rs new file mode 100644 index 0000000000000..56fd5ffa89eea --- /dev/null +++ b/src/test/ui/derives/issue-91550.rs @@ -0,0 +1,29 @@ +use std::collections::HashSet; + +/// natural case from the issue +struct Value(u32); + +fn main() { + let hs = HashSet::::new(); + hs.insert(Value(0)); //~ ERROR +} + +/// synthetic cases +pub struct NoDerives; + +struct Object(T); +impl Object { + fn use_eq(&self) {} +} +impl Object { + fn use_ord(&self) {} +} +impl Object { + fn use_ord_and_partial_ord(&self) {} +} + +fn function(foo: Object) { + foo.use_eq(); //~ ERROR + foo.use_ord(); //~ ERROR + foo.use_ord_and_partial_ord(); //~ ERROR +} diff --git a/src/test/ui/derives/issue-91550.stderr b/src/test/ui/derives/issue-91550.stderr new file mode 100644 index 0000000000000..2b88c35c6a396 --- /dev/null +++ b/src/test/ui/derives/issue-91550.stderr @@ -0,0 +1,84 @@ +error[E0599]: the method `insert` exists for struct `HashSet`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:8:8 + | +LL | struct Value(u32); + | ------------------ + | | + | doesn't satisfy `Value: Eq` + | doesn't satisfy `Value: Hash` +... +LL | hs.insert(Value(0)); + | ^^^^^^ method cannot be called on `HashSet` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Value: Eq` + `Value: Hash` +help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]` + | +LL | #[derive(Eq, Hash, PartialEq)] + | + +error[E0599]: the method `use_eq` exists for struct `Object`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:26:9 + | +LL | pub struct NoDerives; + | --------------------- doesn't satisfy `NoDerives: Eq` +LL | +LL | struct Object(T); + | -------------------- method `use_eq` not found for this +... +LL | foo.use_eq(); + | ^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Eq` +help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]` + | +LL | #[derive(Eq, PartialEq)] + | + +error[E0599]: the method `use_ord` exists for struct `Object`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:27:9 + | +LL | pub struct NoDerives; + | --------------------- doesn't satisfy `NoDerives: Ord` +LL | +LL | struct Object(T); + | -------------------- method `use_ord` not found for this +... +LL | foo.use_ord(); + | ^^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Ord` +help: consider annotating `NoDerives` with `#[derive(Ord, PartialOrd)]` + | +LL | #[derive(Ord, PartialOrd)] + | + +error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object`, but its trait bounds were not satisfied + --> $DIR/issue-91550.rs:28:9 + | +LL | pub struct NoDerives; + | --------------------- + | | + | doesn't satisfy `NoDerives: Ord` + | doesn't satisfy `NoDerives: PartialOrd` +LL | +LL | struct Object(T); + | -------------------- method `use_ord_and_partial_ord` not found for this +... +LL | foo.use_ord_and_partial_ord(); + | ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `NoDerives: Ord` + `NoDerives: PartialOrd` +help: consider annotating `NoDerives` with `#[derive(Ord, PartialOrd)]` + | +LL | #[derive(Ord, PartialOrd)] + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0599`. From ae212402d664a054a9e9a46b6e57f388ef2c2e74 Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Sat, 12 Feb 2022 17:43:21 +1100 Subject: [PATCH 05/10] Make implementation generic --- .../rustc_typeck/src/check/method/suggest.rs | 50 +++++++++++-------- src/test/ui/binop/issue-28837.stderr | 16 +++--- src/test/ui/derives/issue-91550.stderr | 8 +-- .../union-derive-clone.mirunsafeck.stderr | 4 +- .../union-derive-clone.thirunsafeck.stderr | 4 +- 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 5b06cc333027e..7f9f1a3270185 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1196,10 +1196,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(adt) if adt.did.is_local() => adt, _ => continue, }; - let diagnostic_name = self.tcx.get_diagnostic_name(trait_pred.def_id()); - let can_derive = match diagnostic_name { - Some(sym::Default) => !adt.is_enum(), - Some( + if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) { + let can_derive = match diagnostic_name { + sym::Default => !adt.is_enum(), sym::Eq | sym::PartialEq | sym::Ord @@ -1207,24 +1206,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | sym::Clone | sym::Copy | sym::Hash - | sym::Debug, - ) => true, - _ => false, - }; - if can_derive { - let self_name = trait_pred.self_ty().to_string(); - let self_span = self.tcx.def_span(adt.did); - if let Some(sym::Ord) = diagnostic_name { - derives.push((self_name.clone(), self_span.clone(), "PartialOrd".to_string())); - } - if let Some(sym::Eq) = diagnostic_name { - derives.push((self_name.clone(), self_span.clone(), "PartialEq".to_string())); + | sym::Debug => true, + _ => false, + }; + if can_derive { + let self_name = trait_pred.self_ty().to_string(); + let self_span = self.tcx.def_span(adt.did); + use crate::rustc_middle::ty::ToPolyTraitRef; + if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() { + for super_trait in rustc_middle::traits::util::supertraits( + self.tcx, + poly_trait_ref.to_poly_trait_ref(), + ) { + if let Some(parent_diagnostic_name) = + self.tcx.get_diagnostic_name(super_trait.def_id()) + { + derives.push(( + self_name.clone(), + self_span.clone(), + parent_diagnostic_name.to_string(), + )); + } + } + } + derives.push((self_name, self_span, diagnostic_name.to_string())); + } else { + traits.push(self.tcx.def_span(trait_pred.def_id())); } - derives.push(( - self_name, - self_span, - trait_pred.trait_ref.print_only_trait_name().to_string(), - )); } else { traits.push(self.tcx.def_span(trait_pred.def_id())); } diff --git a/src/test/ui/binop/issue-28837.stderr b/src/test/ui/binop/issue-28837.stderr index 10f243bab1586..1875ea06a06d5 100644 --- a/src/test/ui/binop/issue-28837.stderr +++ b/src/test/ui/binop/issue-28837.stderr @@ -272,9 +272,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `<=` cannot be applied to type `A` @@ -290,9 +290,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `>` cannot be applied to type `A` @@ -308,9 +308,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error[E0369]: binary operation `>=` cannot be applied to type `A` @@ -326,9 +326,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A` | LL | struct A; | ^^^^^^^^^ must implement `PartialOrd<_>` -help: consider annotating `A` with `#[derive(PartialOrd)]` +help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]` | -LL | #[derive(PartialOrd)] +LL | #[derive(PartialEq, PartialOrd)] | error: aborting due to 15 previous errors diff --git a/src/test/ui/derives/issue-91550.stderr b/src/test/ui/derives/issue-91550.stderr index 2b88c35c6a396..bf4b7c7da0d50 100644 --- a/src/test/ui/derives/issue-91550.stderr +++ b/src/test/ui/derives/issue-91550.stderr @@ -51,9 +51,9 @@ LL | foo.use_ord(); | = note: the following trait bounds were not satisfied: `NoDerives: Ord` -help: consider annotating `NoDerives` with `#[derive(Ord, PartialOrd)]` +help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | -LL | #[derive(Ord, PartialOrd)] +LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] | error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object`, but its trait bounds were not satisfied @@ -74,9 +74,9 @@ LL | foo.use_ord_and_partial_ord(); = note: the following trait bounds were not satisfied: `NoDerives: Ord` `NoDerives: PartialOrd` -help: consider annotating `NoDerives` with `#[derive(Ord, PartialOrd)]` +help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | -LL | #[derive(Ord, PartialOrd)] +LL | #[derive(Eq, Ord, PartialEq, PartialOrd)] | error: aborting due to 4 previous errors diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr index 146a627bcdef7..e8e65fe5d1d1d 100644 --- a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr @@ -16,9 +16,9 @@ LL | let w = u.clone(); = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` which is required by `U5: Clone` -help: consider annotating `CloneNoCopy` with `#[derive(Copy)]` +help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Copy)] +LL | #[derive(Clone, Copy)] | error[E0277]: the trait bound `U1: Copy` is not satisfied diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr index 146a627bcdef7..e8e65fe5d1d1d 100644 --- a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr +++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr @@ -16,9 +16,9 @@ LL | let w = u.clone(); = note: the following trait bounds were not satisfied: `CloneNoCopy: Copy` which is required by `U5: Clone` -help: consider annotating `CloneNoCopy` with `#[derive(Copy)]` +help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]` | -LL | #[derive(Copy)] +LL | #[derive(Clone, Copy)] | error[E0277]: the trait bound `U1: Copy` is not satisfied From 1973f277a3e79861df2f5bff88aedaf127d833c8 Mon Sep 17 00:00:00 2001 From: Lucas Kent Date: Wed, 16 Feb 2022 15:01:19 +1100 Subject: [PATCH 06/10] Cleanup uses --- compiler/rustc_typeck/src/check/method/suggest.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 7f9f1a3270185..fc9e14b0000c0 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -9,8 +9,10 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::traits::util::supertraits; use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams}; use rustc_middle::ty::print::with_crate_prefix; +use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_span::lev_distance; use rustc_span::symbol::{kw, sym, Ident}; @@ -1212,12 +1214,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if can_derive { let self_name = trait_pred.self_ty().to_string(); let self_span = self.tcx.def_span(adt.did); - use crate::rustc_middle::ty::ToPolyTraitRef; if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() { - for super_trait in rustc_middle::traits::util::supertraits( - self.tcx, - poly_trait_ref.to_poly_trait_ref(), - ) { + for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref()) + { if let Some(parent_diagnostic_name) = self.tcx.get_diagnostic_name(super_trait.def_id()) { From 91adb6ccd693737aaf740bc18bc6f82e3898d322 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 16 Feb 2022 00:38:04 +0000 Subject: [PATCH 07/10] Correctly mark the span of captured arguments in `format_args!()` It should only include the identifier, or misspelling suggestions will be wrong. --- compiler/rustc_builtin_macros/src/asm.rs | 4 +-- compiler/rustc_builtin_macros/src/format.rs | 26 +++++++++---------- compiler/rustc_parse_format/src/lib.rs | 16 +++++++----- compiler/rustc_parse_format/src/tests.rs | 4 +-- .../src/traits/on_unimplemented.rs | 16 ++++++------ .../bad-template.aarch64_mirunsafeck.stderr | 8 +++--- .../bad-template.aarch64_thirunsafeck.stderr | 8 +++--- .../bad-template.x86_64_mirunsafeck.stderr | 8 +++--- .../bad-template.x86_64_thirunsafeck.stderr | 8 +++--- .../format-args-capture-issue-93378.stderr | 8 +++--- .../ui/fmt/format-args-capture-issue-94010.rs | 7 +++++ .../format-args-capture-issue-94010.stderr | 20 ++++++++++++++ ...rmat-args-capture-missing-variables.stderr | 24 ++++++++--------- src/test/ui/fmt/ifmt-bad-arg.stderr | 20 +++++++------- src/tools/clippy/clippy_lints/src/write.rs | 2 +- 15 files changed, 105 insertions(+), 74 deletions(-) create mode 100644 src/test/ui/fmt/format-args-capture-issue-94010.rs create mode 100644 src/test/ui/fmt/format-args-capture-issue-94010.stderr diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 1a6e56947916f..ac37c4973d870 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -700,11 +700,11 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option match args.named_args.get(&name) { + parse::ArgumentNamed(name, span) => match args.named_args.get(&name) { Some(&idx) => Some(idx), None => { let msg = format!("there is no argument named `{}`", name); - ecx.struct_span_err(span, &msg).emit(); + ecx.struct_span_err(template_span.from_inner(span), &msg).emit(); None } }, diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 584fbd1b605cd..6141d00f69712 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -11,7 +11,7 @@ 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}; +use rustc_span::{InnerSpan, MultiSpan, Span}; use smallvec::SmallVec; use std::borrow::Cow; @@ -26,7 +26,7 @@ enum ArgumentType { enum Position { Exact(usize), Capture(usize), - Named(Symbol), + Named(Symbol, InnerSpan), } struct Context<'a, 'b> { @@ -247,13 +247,13 @@ impl<'a, 'b> Context<'a, 'b> { match *p { parse::String(_) => {} parse::NextArgument(ref mut arg) => { - if let parse::ArgumentNamed(s) = arg.position { + if let parse::ArgumentNamed(s, _) = arg.position { arg.position = parse::ArgumentIs(lookup(s)); } - if let parse::CountIsName(s) = arg.format.width { + if let parse::CountIsName(s, _) = arg.format.width { arg.format.width = parse::CountIsParam(lookup(s)); } - if let parse::CountIsName(s) = arg.format.precision { + if let parse::CountIsName(s, _) = arg.format.precision { arg.format.precision = parse::CountIsParam(lookup(s)); } } @@ -276,7 +276,7 @@ impl<'a, 'b> Context<'a, 'b> { // it's written second, so it should come after width/precision. let pos = match arg.position { parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i), - parse::ArgumentNamed(s) => Named(s), + parse::ArgumentNamed(s, span) => Named(s, span), }; let ty = Placeholder(match arg.format.ty { @@ -346,8 +346,8 @@ impl<'a, 'b> Context<'a, 'b> { parse::CountIsParam(i) => { self.verify_arg_type(Exact(i), Count); } - parse::CountIsName(s) => { - self.verify_arg_type(Named(s), Count); + parse::CountIsName(s, span) => { + self.verify_arg_type(Named(s, span), Count); } } } @@ -533,7 +533,7 @@ impl<'a, 'b> Context<'a, 'b> { } } - Named(name) => { + Named(name, span) => { match self.names.get(&name) { Some(&idx) => { // Treat as positional arg. @@ -548,7 +548,7 @@ impl<'a, 'b> Context<'a, 'b> { self.arg_types.push(Vec::new()); self.arg_unique_types.push(Vec::new()); let span = if self.is_literal { - *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp) + self.fmtsp.from_inner(span) } else { self.fmtsp }; @@ -559,7 +559,7 @@ impl<'a, 'b> Context<'a, 'b> { } else { let msg = format!("there is no argument named `{}`", name); let sp = if self.is_literal { - *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp) + self.fmtsp.from_inner(span) } else { self.fmtsp }; @@ -629,7 +629,7 @@ impl<'a, 'b> Context<'a, 'b> { } parse::CountImplied => count(sym::Implied, None), // should never be the case, names are already resolved - parse::CountIsName(_) => panic!("should never happen"), + parse::CountIsName(..) => panic!("should never happen"), } } @@ -676,7 +676,7 @@ impl<'a, 'b> Context<'a, 'b> { // should never be the case, because names are already // resolved. - parse::ArgumentNamed(_) => panic!("should never happen"), + parse::ArgumentNamed(..) => panic!("should never happen"), } }; diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 9d653de910fec..a6a2cbc277c20 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -95,7 +95,7 @@ pub enum Position { /// The argument is located at a specific index given in the format ArgumentIs(usize), /// The argument has a name. - ArgumentNamed(Symbol), + ArgumentNamed(Symbol, InnerSpan), } impl Position { @@ -147,7 +147,7 @@ pub enum Count { /// The count is specified explicitly. CountIs(usize), /// The count is specified by the argument with the given name. - CountIsName(Symbol), + CountIsName(Symbol, InnerSpan), /// The count is specified by the argument at the given index. CountIsParam(usize), /// The count is implied and cannot be explicitly specified. @@ -494,8 +494,11 @@ impl<'a> Parser<'a> { Some(ArgumentIs(i)) } else { match self.cur.peek() { - Some(&(_, c)) if rustc_lexer::is_id_start(c) => { - Some(ArgumentNamed(Symbol::intern(self.word()))) + Some(&(start, c)) if rustc_lexer::is_id_start(c) => { + let word = self.word(); + let end = start + word.len(); + let span = self.to_span_index(start).to(self.to_span_index(end)); + Some(ArgumentNamed(Symbol::intern(word), span)) } // This is an `ArgumentNext`. @@ -662,8 +665,9 @@ impl<'a> Parser<'a> { if word.is_empty() { self.cur = tmp; (CountImplied, None) - } else if self.consume('$') { - (CountIsName(Symbol::intern(word)), None) + } else if let Some(end) = self.consume_pos('$') { + let span = self.to_span_index(start + 1).to(self.to_span_index(end)); + (CountIsName(Symbol::intern(word), span), None) } else { self.cur = tmp; (CountImplied, None) diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index b7693a85ad955..6c960fdc72bfd 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -221,8 +221,8 @@ fn format_counts() { fill: None, align: AlignUnknown, flags: 0, - precision: CountIsName(Symbol::intern("b")), - width: CountIsName(Symbol::intern("a")), + precision: CountIsName(Symbol::intern("b"), InnerSpan::new(6, 7)), + width: CountIsName(Symbol::intern("a"), InnerSpan::new(4, 4)), precision_span: None, width_span: None, ty: "?", diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index bdf677a63b632..b05dbbe898a41 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -309,23 +309,23 @@ impl<'tcx> OnUnimplementedFormatString { Piece::String(_) => (), // Normal string, no need to check it Piece::NextArgument(a) => match a.position { // `{Self}` is allowed - Position::ArgumentNamed(s) if s == kw::SelfUpper => (), + Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (), // `{ThisTraitsName}` is allowed - Position::ArgumentNamed(s) if s == name => (), + Position::ArgumentNamed(s, _) if s == name => (), // `{from_method}` is allowed - Position::ArgumentNamed(s) if s == sym::from_method => (), + Position::ArgumentNamed(s, _) if s == sym::from_method => (), // `{from_desugaring}` is allowed - Position::ArgumentNamed(s) if s == sym::from_desugaring => (), + Position::ArgumentNamed(s, _) if s == sym::from_desugaring => (), // `{ItemContext}` is allowed - Position::ArgumentNamed(s) if s == sym::ItemContext => (), + Position::ArgumentNamed(s, _) if s == sym::ItemContext => (), // `{integral}` and `{integer}` and `{float}` are allowed - Position::ArgumentNamed(s) + Position::ArgumentNamed(s, _) if s == sym::integral || s == sym::integer_ || s == sym::float => { () } // So is `{A}` if A is a type parameter - Position::ArgumentNamed(s) => { + Position::ArgumentNamed(s, _) => { match generics.params.iter().find(|param| param.name == s) { Some(_) => (), None => { @@ -392,7 +392,7 @@ impl<'tcx> OnUnimplementedFormatString { .map(|p| match p { Piece::String(s) => s, Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => match generic_map.get(&s) { + Position::ArgumentNamed(s, _) => match generic_map.get(&s) { Some(val) => val, None if s == name => &trait_str, None => { diff --git a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr index 3b1d922a7f757..11c4e01f4186d 100644 --- a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr @@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:36:15 + --> $DIR/bad-template.rs:36:16 | LL | asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:38:15 @@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:14 + --> $DIR/bad-template.rs:63:15 | LL | global_asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:65:14 diff --git a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr index 3b1d922a7f757..11c4e01f4186d 100644 --- a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr @@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:36:15 + --> $DIR/bad-template.rs:36:16 | LL | asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:38:15 @@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:14 + --> $DIR/bad-template.rs:63:15 | LL | global_asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:65:14 diff --git a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr index 3b69186f1e18b..c198e0a69dde1 100644 --- a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr @@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:36:15 + --> $DIR/bad-template.rs:36:16 | LL | asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:38:15 @@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:14 + --> $DIR/bad-template.rs:63:15 | LL | global_asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:65:14 diff --git a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr index 3b69186f1e18b..c198e0a69dde1 100644 --- a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr @@ -23,10 +23,10 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:36:15 + --> $DIR/bad-template.rs:36:16 | LL | asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:38:15 @@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:63:14 + --> $DIR/bad-template.rs:63:15 | LL | global_asm!("{a}"); - | ^^^ + | ^ error: invalid reference to argument at index 0 --> $DIR/bad-template.rs:65:14 diff --git a/src/test/ui/fmt/format-args-capture-issue-93378.stderr b/src/test/ui/fmt/format-args-capture-issue-93378.stderr index 588541044fe13..b8e2b2afb3867 100644 --- a/src/test/ui/fmt/format-args-capture-issue-93378.stderr +++ b/src/test/ui/fmt/format-args-capture-issue-93378.stderr @@ -10,10 +10,10 @@ error: invalid reference to positional argument 0 (no arguments were given) --> $DIR/format-args-capture-issue-93378.rs:9:23 | LL | println!("{a:.n$} {b:.*}"); - | ------- ^^^--^ - | | | - | | this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected - | this parameter corresponds to the precision flag + | - ^^^--^ + | | | + | | this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected + | this parameter corresponds to the precision flag | = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html diff --git a/src/test/ui/fmt/format-args-capture-issue-94010.rs b/src/test/ui/fmt/format-args-capture-issue-94010.rs new file mode 100644 index 0000000000000..bd03e9c93ae2a --- /dev/null +++ b/src/test/ui/fmt/format-args-capture-issue-94010.rs @@ -0,0 +1,7 @@ +fn main() { + const FOO: i32 = 123; + println!("{foo:X}"); + //~^ ERROR: cannot find value `foo` in this scope + println!("{:.foo$}", 0); + //~^ ERROR: cannot find value `foo` in this scope +} diff --git a/src/test/ui/fmt/format-args-capture-issue-94010.stderr b/src/test/ui/fmt/format-args-capture-issue-94010.stderr new file mode 100644 index 0000000000000..ed90dc855360a --- /dev/null +++ b/src/test/ui/fmt/format-args-capture-issue-94010.stderr @@ -0,0 +1,20 @@ +error[E0425]: cannot find value `foo` in this scope + --> $DIR/format-args-capture-issue-94010.rs:3:16 + | +LL | const FOO: i32 = 123; + | --------------------- similarly named constant `FOO` defined here +LL | println!("{foo:X}"); + | ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO` + +error[E0425]: cannot find value `foo` in this scope + --> $DIR/format-args-capture-issue-94010.rs:5:18 + | +LL | const FOO: i32 = 123; + | --------------------- similarly named constant `FOO` defined here +... +LL | println!("{:.foo$}", 0); + | ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.stderr b/src/test/ui/fmt/format-args-capture-missing-variables.stderr index d53c206003f94..d980e7be273e8 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.stderr +++ b/src/test/ui/fmt/format-args-capture-missing-variables.stderr @@ -7,40 +7,40 @@ LL | format!("{valuea} {valueb}", valuea=5, valuec=7); | formatting specifier missing error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:2:17 + --> $DIR/format-args-capture-missing-variables.rs:2:18 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `bar` in this scope - --> $DIR/format-args-capture-missing-variables.rs:2:26 + --> $DIR/format-args-capture-missing-variables.rs:2:27 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:6:14 + --> $DIR/format-args-capture-missing-variables.rs:6:15 | LL | format!("{foo}"); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `valueb` in this scope - --> $DIR/format-args-capture-missing-variables.rs:8:23 + --> $DIR/format-args-capture-missing-variables.rs:8:24 | LL | format!("{valuea} {valueb}", valuea=5, valuec=7); - | ^^^^^^^^ not found in this scope + | ^^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:14:9 + --> $DIR/format-args-capture-missing-variables.rs:14:10 | LL | {foo} - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:19:13 + --> $DIR/format-args-capture-missing-variables.rs:19:14 | LL | panic!("{foo} {bar}", bar=1); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error: aborting due to 7 previous errors diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr index acc4e95f5bb7e..3f1f1006713ba 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.stderr +++ b/src/test/ui/fmt/ifmt-bad-arg.stderr @@ -263,34 +263,34 @@ LL | println!("{:.*}"); = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html error[E0425]: cannot find value `foo` in this scope - --> $DIR/ifmt-bad-arg.rs:27:17 + --> $DIR/ifmt-bad-arg.rs:27:18 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `bar` in this scope - --> $DIR/ifmt-bad-arg.rs:27:26 + --> $DIR/ifmt-bad-arg.rs:27:27 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/ifmt-bad-arg.rs:31:14 + --> $DIR/ifmt-bad-arg.rs:31:15 | LL | format!("{foo}"); - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0425]: cannot find value `valueb` in this scope - --> $DIR/ifmt-bad-arg.rs:45:23 + --> $DIR/ifmt-bad-arg.rs:45:24 | LL | format!("{valuea} {valueb}", valuea=5, valuec=7); - | ^^^^^^^^ not found in this scope + | ^^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/ifmt-bad-arg.rs:60:9 + --> $DIR/ifmt-bad-arg.rs:60:10 | LL | {foo} - | ^^^^^ not found in this scope + | ^^^ not found in this scope error[E0308]: mismatched types --> $DIR/ifmt-bad-arg.rs:78:32 diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index b0044695ea8a8..1fa6301ebd73d 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -453,7 +453,7 @@ impl SimpleFormatArgs { } } }, - ArgumentNamed(n) => { + ArgumentNamed(n, _) => { if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) { match x.1.as_slice() { // A non-empty format string has been seen already. From 6d2cdbec3ef6e5460753986372ed898a1b3bc553 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Tue, 15 Feb 2022 20:16:19 +0100 Subject: [PATCH 08/10] Add mentions to `Copy` for `union` fields --- compiler/rustc_typeck/src/check/check.rs | 9 +++++++-- .../feature-gates/feature-gate-untagged_unions.rs | 4 ++-- .../feature-gate-untagged_unions.stderr | 10 ++++++---- src/test/ui/union/issue-41073.rs | 2 +- src/test/ui/union/issue-41073.stderr | 5 +++-- src/test/ui/union/union-custom-drop.rs | 2 +- src/test/ui/union/union-custom-drop.stderr | 5 +++-- .../union-with-drop-fields.mirunsafeck.stderr | 15 +++++++++------ src/test/ui/union/union-with-drop-fields.rs | 6 +++--- .../union-with-drop-fields.thirunsafeck.stderr | 15 +++++++++------ 10 files changed, 44 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 423abc3227db6..ca2e75886c794 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -382,10 +382,15 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b tcx.sess, field_span, E0740, - "unions may not contain fields that need dropping" + "unions cannot contain fields that may need dropping" + ) + .note( + "a type is guaranteed not to need dropping \ + when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type", ) .multipart_suggestion_verbose( - "wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped", + "when the type does not implement `Copy`, \ + wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped", vec![ (ty_span.shrink_to_lo(), format!("std::mem::ManuallyDrop<")), (ty_span.shrink_to_hi(), ">".into()), diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index f5f9631c3bcf9..af8d8e92b20bd 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -13,7 +13,7 @@ union U22 { // OK } union U3 { - a: String, //~ ERROR unions may not contain fields that need dropping + a: String, //~ ERROR unions cannot contain fields that may need dropping } union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! @@ -21,7 +21,7 @@ union U32 { // field that does not drop but is not `Copy`, either -- this is the } union U4 { - a: T, //~ ERROR unions may not contain fields that need dropping + a: T, //~ ERROR unions cannot contain fields that may need dropping } union U5 { // Having a drop impl is OK diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 0967cb7ba8bd2..9e4a89f80c852 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -7,24 +7,26 @@ LL | a: std::cell::RefCell, = note: see issue #55149 for more information = help: add `#![feature(untagged_unions)]` to the crate attributes to enable -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/feature-gate-untagged_unions.rs:16:5 | LL | a: String, | ^^^^^^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/feature-gate-untagged_unions.rs:24:5 | LL | a: T, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + diff --git a/src/test/ui/union/issue-41073.rs b/src/test/ui/union/issue-41073.rs index 91e9a0d0b659c..80474b807e7f3 100644 --- a/src/test/ui/union/issue-41073.rs +++ b/src/test/ui/union/issue-41073.rs @@ -1,7 +1,7 @@ #![feature(untagged_unions)] union Test { - a: A, //~ ERROR unions may not contain fields that need dropping + a: A, //~ ERROR unions cannot contain fields that may need dropping b: B } diff --git a/src/test/ui/union/issue-41073.stderr b/src/test/ui/union/issue-41073.stderr index 8edf4db441b9c..7d4208b10da80 100644 --- a/src/test/ui/union/issue-41073.stderr +++ b/src/test/ui/union/issue-41073.stderr @@ -1,10 +1,11 @@ -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/issue-41073.rs:4:5 | LL | a: A, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + diff --git a/src/test/ui/union/union-custom-drop.rs b/src/test/ui/union/union-custom-drop.rs index 8f816cc1b737c..4b333631ec0f7 100644 --- a/src/test/ui/union/union-custom-drop.rs +++ b/src/test/ui/union/union-custom-drop.rs @@ -4,7 +4,7 @@ #![feature(untagged_unions)] union Foo { - bar: Bar, //~ ERROR unions may not contain fields that need dropping + bar: Bar, //~ ERROR unions cannot contain fields that may need dropping } union Bar { diff --git a/src/test/ui/union/union-custom-drop.stderr b/src/test/ui/union/union-custom-drop.stderr index 65ca5fd931d67..b5579eeef0977 100644 --- a/src/test/ui/union/union-custom-drop.stderr +++ b/src/test/ui/union/union-custom-drop.stderr @@ -1,10 +1,11 @@ -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-custom-drop.rs:7:5 | LL | bar: Bar, | ^^^^^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | bar: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + diff --git a/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr b/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr index f5e9681735c6f..93fe996d2a477 100644 --- a/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr +++ b/src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr @@ -1,32 +1,35 @@ -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:11:5 | LL | a: String, | ^^^^^^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:19:5 | LL | a: S, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:24:5 | LL | a: T, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + diff --git a/src/test/ui/union/union-with-drop-fields.rs b/src/test/ui/union/union-with-drop-fields.rs index 96c293418b629..a7a8b69e784ab 100644 --- a/src/test/ui/union/union-with-drop-fields.rs +++ b/src/test/ui/union/union-with-drop-fields.rs @@ -8,7 +8,7 @@ union U { } union W { - a: String, //~ ERROR unions may not contain fields that need dropping + a: String, //~ ERROR unions cannot contain fields that may need dropping b: String, // OK, only one field is reported } @@ -16,12 +16,12 @@ struct S(String); // `S` doesn't implement `Drop` trait, but still has non-trivial destructor union Y { - a: S, //~ ERROR unions may not contain fields that need dropping + a: S, //~ ERROR unions cannot contain fields that may need dropping } // We don't know if `T` is trivially-destructable or not until trans union J { - a: T, //~ ERROR unions may not contain fields that need dropping + a: T, //~ ERROR unions cannot contain fields that may need dropping } union H { diff --git a/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr b/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr index f5e9681735c6f..93fe996d2a477 100644 --- a/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr +++ b/src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr @@ -1,32 +1,35 @@ -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:11:5 | LL | a: String, | ^^^^^^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:19:5 | LL | a: S, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + -error[E0740]: unions may not contain fields that need dropping +error[E0740]: unions cannot contain fields that may need dropping --> $DIR/union-with-drop-fields.rs:24:5 | LL | a: T, | ^^^^ | -help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped + = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type +help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped | LL | a: std::mem::ManuallyDrop, | +++++++++++++++++++++++ + From 65fc7058d88f28f6fa33970ef866b59e33f4255b Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 13 Feb 2022 13:06:06 -0700 Subject: [PATCH 09/10] Do not suggest "is a function" for free variables Part of #82323 --- .../rustc_typeck/src/check/method/suggest.rs | 12 +++++++ ...n-help-with-err-generic-is-not-function.rs | 22 +++++++++++++ ...lp-with-err-generic-is-not-function.stderr | 32 +++++++++++++++++++ .../ui/functions-closures/fn-help-with-err.rs | 16 ++++++++++ .../fn-help-with-err.stderr | 24 ++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs create mode 100644 src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr create mode 100644 src/test/ui/functions-closures/fn-help-with-err.rs create mode 100644 src/test/ui/functions-closures/fn-help-with-err.stderr diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 8aa22852a6ffd..f2b228fa00268 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -40,7 +40,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(..) => return false, }; + // This conditional prevents us from asking to call errors and unresolved types. + // It might seem that we can use `predicate_must_hold_modulo_regions`, + // but since a Dummy binder is used to fill in the FnOnce trait's arguments, + // type resolution always gives a "maybe" here. + if self.autoderef(span, ty).any(|(ty, _)| { + info!("check deref {:?} error", ty); + matches!(ty.kind(), ty::Error(_) | ty::Infer(_)) + }) { + return false; + } + self.autoderef(span, ty).any(|(ty, _)| { + info!("check deref {:?} impl FnOnce", ty); self.probe(|_| { let fn_once_substs = tcx.mk_substs_trait( ty, diff --git a/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs new file mode 100644 index 0000000000000..26deb59876268 --- /dev/null +++ b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs @@ -0,0 +1,22 @@ +struct Struct(T); +impl Struct +//~^ ERROR cannot find type `T` in this scope +//~| NOTE not found in this scope +//~| HELP you might be missing a type parameter +where + T: Copy, + //~^ ERROR cannot find type `T` in this scope + //~| NOTE not found in this scope +{ + // The part where it claims that there is no method named `len` is a bug. Feel free to fix it. + // This test is intended to ensure that a different bug, where it claimed + // that `v` was a function, does not regress. + fn method(v: Vec) { v.len(); } + //~^ ERROR type annotations needed + //~| NOTE cannot infer type + //~| NOTE type must be known at this point + //~| ERROR no method named `len` + //~| NOTE private field, not a method +} + +fn main() {} diff --git a/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr new file mode 100644 index 0000000000000..958ce3c25d027 --- /dev/null +++ b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr @@ -0,0 +1,32 @@ +error[E0412]: cannot find type `T` in this scope + --> $DIR/fn-help-with-err-generic-is-not-function.rs:2:13 + | +LL | impl Struct + | - ^ not found in this scope + | | + | help: you might be missing a type parameter: `` + +error[E0412]: cannot find type `T` in this scope + --> $DIR/fn-help-with-err-generic-is-not-function.rs:7:5 + | +LL | T: Copy, + | ^ not found in this scope + +error[E0282]: type annotations needed + --> $DIR/fn-help-with-err-generic-is-not-function.rs:14:31 + | +LL | fn method(v: Vec) { v.len(); } + | ^^^ cannot infer type + | + = note: type must be known at this point + +error[E0599]: no method named `len` found for struct `Vec` in the current scope + --> $DIR/fn-help-with-err-generic-is-not-function.rs:14:31 + | +LL | fn method(v: Vec) { v.len(); } + | ^^^ private field, not a method + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0282, E0412, E0599. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/functions-closures/fn-help-with-err.rs b/src/test/ui/functions-closures/fn-help-with-err.rs new file mode 100644 index 0000000000000..f8a81af786f7e --- /dev/null +++ b/src/test/ui/functions-closures/fn-help-with-err.rs @@ -0,0 +1,16 @@ +// This test case checks the behavior of typeck::check::method::suggest::is_fn on Ty::Error. +fn main() { + let arc = std::sync::Arc::new(oops); + //~^ ERROR cannot find value `oops` in this scope + //~| NOTE not found + // The error "note: `arc` is a function, perhaps you wish to call it" MUST NOT appear. + arc.blablabla(); + //~^ ERROR no method named `blablabla` + //~| NOTE method not found + let arc2 = std::sync::Arc::new(|| 1); + // The error "note: `arc2` is a function, perhaps you wish to call it" SHOULD appear + arc2.blablabla(); + //~^ ERROR no method named `blablabla` + //~| NOTE method not found + //~| NOTE `arc2` is a function, perhaps you wish to call it +} diff --git a/src/test/ui/functions-closures/fn-help-with-err.stderr b/src/test/ui/functions-closures/fn-help-with-err.stderr new file mode 100644 index 0000000000000..4d6b3282ad9e9 --- /dev/null +++ b/src/test/ui/functions-closures/fn-help-with-err.stderr @@ -0,0 +1,24 @@ +error[E0425]: cannot find value `oops` in this scope + --> $DIR/fn-help-with-err.rs:3:35 + | +LL | let arc = std::sync::Arc::new(oops); + | ^^^^ not found in this scope + +error[E0599]: no method named `blablabla` found for struct `Arc<_>` in the current scope + --> $DIR/fn-help-with-err.rs:7:9 + | +LL | arc.blablabla(); + | ^^^^^^^^^ method not found in `Arc<_>` + +error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>` in the current scope + --> $DIR/fn-help-with-err.rs:12:10 + | +LL | arc2.blablabla(); + | ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>` + | + = note: `arc2` is a function, perhaps you wish to call it + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`. From 8630085ed61c9891089a56c0a25dfdca790dbef7 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 16 Feb 2022 20:03:40 +0100 Subject: [PATCH 10/10] Update dist-x86_64-musl to Ubuntu 20.04 --- src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile index ef49904b53d6a..51645a81853fd 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile @@ -1,6 +1,6 @@ -FROM ubuntu:16.04 +FROM ubuntu:20.04 -RUN apt-get update && apt-get install -y --no-install-recommends \ +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ g++ \ make \ ninja-build \