From f45bdcce69c754a3e5308b71c810e233a100f65c Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 14:20:51 -0500 Subject: [PATCH 01/67] Implement size_hint for BufReader --- library/std/src/io/mod.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index db3b0e2628f2a..0fc99baa66639 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2216,7 +2216,11 @@ impl Read for Chain { unsafe fn initializer(&self) -> Initializer { let initializer = self.first.initializer(); - if initializer.should_initialize() { initializer } else { self.second.initializer() } + if initializer.should_initialize() { + initializer + } else { + self.second.initializer() + } } } @@ -2235,7 +2239,11 @@ impl BufRead for Chain { } fn consume(&mut self, amt: usize) { - if !self.done_first { self.first.consume(amt) } else { self.second.consume(amt) } + if !self.done_first { + self.first.consume(amt) + } else { + self.second.consume(amt) + } } } @@ -2465,6 +2473,17 @@ impl Iterator for Bytes { }; } } + + default fn size_hint(&self) -> (usize, Option) { + (0, None) + } +} + +#[stable(feature = "bufreader_size_hint", since = "1.51.0")] +impl Iterator for Bytes> { + fn size_hint(&self) -> (usize, Option) { + (self.inner.buffer().len(), None) + } } /// An iterator over the contents of an instance of `BufRead` split on a From c3e47d974ab1c1c4d4b00989631586e60d78b554 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 14:43:20 -0500 Subject: [PATCH 02/67] Fix implementation to specialize --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 0fc99baa66639..e02ee58cdbcb2 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2480,7 +2480,7 @@ impl Iterator for Bytes { } #[stable(feature = "bufreader_size_hint", since = "1.51.0")] -impl Iterator for Bytes> { +impl Iterator for Bytes> { fn size_hint(&self) -> (usize, Option) { (self.inner.buffer().len(), None) } From fa76db3104c11416f125be7fcc27d2435dcb84c5 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 17:37:29 -0500 Subject: [PATCH 03/67] Use helper trait to follow min_specialization rules --- library/std/src/io/mod.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index e02ee58cdbcb2..c98f8e383eda0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2459,7 +2459,7 @@ pub struct Bytes { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Bytes { +impl Iterator for Bytes { type Item = Result; fn next(&mut self) -> Option> { @@ -2475,14 +2475,34 @@ impl Iterator for Bytes { } default fn size_hint(&self) -> (usize, Option) { - (0, None) + self.inner.size_hint() } } #[stable(feature = "bufreader_size_hint", since = "1.51.0")] -impl Iterator for Bytes> { +trait SizeHint { + fn lower_bound(&self) -> usize; + + fn upper_bound(&self) -> Option { + None + } + fn size_hint(&self) -> (usize, Option) { - (self.inner.buffer().len(), None) + (self.lower_bound(), self.upper_bound()) + } +} + +#[stable(feature = "bufreader_size_hint", since = "1.51.0")] +impl SizeHint for T { + fn lower_bound(&self) -> usize { + 0 + } +} + +#[stable(feature = "bufreader_size_hint", since = "1.51.0")] +impl SizeHint for BufReader { + fn lower_bound(&self) -> usize { + self.buffer().len() } } From 11c49f6a2a6cc7aa5b0223c4d2ec59fb4fc9b739 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 17:41:42 -0500 Subject: [PATCH 04/67] Add missing generic --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index c98f8e383eda0..ae01972339498 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2493,7 +2493,7 @@ trait SizeHint { } #[stable(feature = "bufreader_size_hint", since = "1.51.0")] -impl SizeHint for T { +impl SizeHint for T { fn lower_bound(&self) -> usize { 0 } From 260a270f7c531a3b8f951b69c9e793e3afd67c89 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 17:47:25 -0500 Subject: [PATCH 05/67] Move default to trait definition --- library/std/src/io/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index ae01972339498..cd54b8cc5699e 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2481,7 +2481,9 @@ impl Iterator for Bytes { #[stable(feature = "bufreader_size_hint", since = "1.51.0")] trait SizeHint { - fn lower_bound(&self) -> usize; + fn lower_bound(&self) -> usize { + 0 + } fn upper_bound(&self) -> Option { None @@ -2493,11 +2495,7 @@ trait SizeHint { } #[stable(feature = "bufreader_size_hint", since = "1.51.0")] -impl SizeHint for T { - fn lower_bound(&self) -> usize { - 0 - } -} +impl SizeHint for T; #[stable(feature = "bufreader_size_hint", since = "1.51.0")] impl SizeHint for BufReader { From 5f60a3048ed0d6b2b56e253769fbd6593ccb1d71 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 17:52:55 -0500 Subject: [PATCH 06/67] Fix incorrect token --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index cd54b8cc5699e..53da24409459d 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2495,7 +2495,7 @@ trait SizeHint { } #[stable(feature = "bufreader_size_hint", since = "1.51.0")] -impl SizeHint for T; +impl SizeHint for T {} #[stable(feature = "bufreader_size_hint", since = "1.51.0")] impl SizeHint for BufReader { From eea99f491b6000a836a8887a29d1ce85c666fe47 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 18:45:00 -0500 Subject: [PATCH 07/67] Add default keyword for specialization --- library/std/src/io/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 53da24409459d..712e808a02474 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2481,10 +2481,6 @@ impl Iterator for Bytes { #[stable(feature = "bufreader_size_hint", since = "1.51.0")] trait SizeHint { - fn lower_bound(&self) -> usize { - 0 - } - fn upper_bound(&self) -> Option { None } @@ -2495,7 +2491,11 @@ trait SizeHint { } #[stable(feature = "bufreader_size_hint", since = "1.51.0")] -impl SizeHint for T {} +impl SizeHint for T { + default fn lower_bound(&self) -> usize { + 0 + } +} #[stable(feature = "bufreader_size_hint", since = "1.51.0")] impl SizeHint for BufReader { From 7e56637c749c4427ce0456022ea84e8393e5b0f7 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 19:29:49 -0500 Subject: [PATCH 08/67] Add back lower_bound as memeber --- library/std/src/io/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 712e808a02474..018fe1c52bfb9 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2481,6 +2481,8 @@ impl Iterator for Bytes { #[stable(feature = "bufreader_size_hint", since = "1.51.0")] trait SizeHint { + fn lower_bound(&self) -> usize { + fn upper_bound(&self) -> Option { None } From 442de9ac4531cc31955b62fbbebf80d2b99b4bb0 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 19:43:52 -0500 Subject: [PATCH 09/67] Fix semicolon --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 018fe1c52bfb9..e9c99e5a62738 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2481,7 +2481,7 @@ impl Iterator for Bytes { #[stable(feature = "bufreader_size_hint", since = "1.51.0")] trait SizeHint { - fn lower_bound(&self) -> usize { + fn lower_bound(&self) -> usize; fn upper_bound(&self) -> Option { None From 1190321b7633369ec9e678d2fe4ac986b8157cc1 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 20:02:55 -0500 Subject: [PATCH 10/67] Remove exposing private trait --- library/std/src/io/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index e9c99e5a62738..a05adedaed2d6 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2459,7 +2459,7 @@ pub struct Bytes { } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Bytes { +impl Iterator for Bytes { type Item = Result; fn next(&mut self) -> Option> { @@ -2475,7 +2475,7 @@ impl Iterator for Bytes { } default fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() + (&self.inner as &SizeHint).size_hint() } } From 421b40cd6a72f039b319f8da6b80c67c385e9965 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 20:09:43 -0500 Subject: [PATCH 11/67] Add dyn for SizeHint cast --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index a05adedaed2d6..e81bfd27a9ad1 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2475,7 +2475,7 @@ impl Iterator for Bytes { } default fn size_hint(&self) -> (usize, Option) { - (&self.inner as &SizeHint).size_hint() + (&self.inner as &dyn SizeHint).size_hint() } } From 265db94dc29b4e089e134795eac24b1b0a2faab1 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 20:25:32 -0500 Subject: [PATCH 12/67] Fix formatting --- library/std/src/io/mod.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index e81bfd27a9ad1..766da2ed6264f 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2216,11 +2216,7 @@ impl Read for Chain { unsafe fn initializer(&self) -> Initializer { let initializer = self.first.initializer(); - if initializer.should_initialize() { - initializer - } else { - self.second.initializer() - } + if initializer.should_initialize() { initializer } else { self.second.initializer() } } } @@ -2239,11 +2235,7 @@ impl BufRead for Chain { } fn consume(&mut self, amt: usize) { - if !self.done_first { - self.first.consume(amt) - } else { - self.second.consume(amt) - } + if !self.done_first { self.first.consume(amt) } else { self.second.consume(amt) } } } From 93870c8d5ff5750db2e138f35f783078e8ad8dd0 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 20:40:10 -0500 Subject: [PATCH 13/67] Remove stable annotation --- library/std/src/io/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 766da2ed6264f..754e22f228821 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2471,7 +2471,6 @@ impl Iterator for Bytes { } } -#[stable(feature = "bufreader_size_hint", since = "1.51.0")] trait SizeHint { fn lower_bound(&self) -> usize; @@ -2484,14 +2483,12 @@ trait SizeHint { } } -#[stable(feature = "bufreader_size_hint", since = "1.51.0")] impl SizeHint for T { default fn lower_bound(&self) -> usize { 0 } } -#[stable(feature = "bufreader_size_hint", since = "1.51.0")] impl SizeHint for BufReader { fn lower_bound(&self) -> usize { self.buffer().len() From 7869371bf1e6ab88bb61771c5dca217cc92ba0c9 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Fri, 15 Jan 2021 20:45:43 -0500 Subject: [PATCH 14/67] Remove unnecessary default keyword --- library/std/src/io/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 754e22f228821..d7fd811cdb64b 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2466,7 +2466,7 @@ impl Iterator for Bytes { } } - default fn size_hint(&self) -> (usize, Option) { + fn size_hint(&self) -> (usize, Option) { (&self.inner as &dyn SizeHint).size_hint() } } @@ -2474,9 +2474,7 @@ impl Iterator for Bytes { trait SizeHint { fn lower_bound(&self) -> usize; - fn upper_bound(&self) -> Option { - None - } + fn upper_bound(&self) -> Option; fn size_hint(&self) -> (usize, Option) { (self.lower_bound(), self.upper_bound()) @@ -2487,6 +2485,10 @@ impl SizeHint for T { default fn lower_bound(&self) -> usize { 0 } + + default fn upper_bound(&self) -> Option { + None + } } impl SizeHint for BufReader { From c8e0f8aaa3e8a21158b596814d8a53cfe604a294 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Sat, 16 Jan 2021 10:42:52 -0500 Subject: [PATCH 15/67] Use fully qualified syntax to avoid dyn --- library/std/src/io/mod.rs | 2 +- library/std/src/io/tests.rs | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index d7fd811cdb64b..3839f7cd28d17 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2467,7 +2467,7 @@ impl Iterator for Bytes { } fn size_hint(&self) -> (usize, Option) { - (&self.inner as &dyn SizeHint).size_hint() + SizeHint::size_hint(&self.inner) } } diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f176c2f088cb3..03ed8ba74c520 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -1,7 +1,7 @@ use super::{repeat, Cursor, SeekFrom}; use crate::cmp::{self, min}; use crate::io::{self, IoSlice, IoSliceMut}; -use crate::io::{BufRead, Read, Seek, Write}; +use crate::io::{BufRead, BufReader, Read, Seek, Write}; use crate::ops::Deref; #[test] @@ -198,6 +198,26 @@ fn chain_bufread() { cmp_bufread(chain1, chain2, &testdata[..]); } +#[test] +fn bufreader_size_hint() { + let testdata = b"ABCDEFGHIJKL"; + let mut buf_reader = BufReader::new(&testdata[..]); + assert_eq!(buf_reader.buffer().len(), 0); + + let buffer = buf_reader.fill_buf().unwrap(); + let buffer_length = buffer.len(); + + // Check that size hint matches buffer contents + let mut buffered_bytes = buf_reader.bytes(); + let (lower_bound, _upper_bound) = buffered_bytes.size_hint(); + assert_eq!(lower_bound, buffer_length); + + // Check that size hint matches buffer contents after advancing + buffered_bytes.next().unwrap().unwrap(); + let (lower_bound, _upper_bound) = buffered_bytes.size_hint(); + assert_eq!(lower_bound, buffer_length - 1); +} + #[test] fn chain_zero_length_read_is_not_eof() { let a = b"A"; From 96255f82c9209fc2366ef32937c2bb53817687c1 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Sat, 16 Jan 2021 15:03:58 -0500 Subject: [PATCH 16/67] Implement SizeHint trait for BufReader, Emtpy, and Chain --- library/std/src/io/buffered/bufreader.rs | 9 ++++++++- library/std/src/io/mod.rs | 20 ++++++++++++++------ library/std/src/io/util.rs | 8 +++++++- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 987371f50ec22..e737a104014f4 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -1,6 +1,6 @@ use crate::cmp; use crate::fmt; -use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE}; +use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE}; /// The `BufReader` struct adds buffering to any reader. /// @@ -435,3 +435,10 @@ impl Seek for BufReader { }) } } + +impl SizeHint for BufReader { + fn lower_bound(&self) -> usize { + self.buffer().len() + } +} + diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 3839f7cd28d17..08b258bb816ec 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2239,6 +2239,20 @@ impl BufRead for Chain { } } +impl SizeHint for Chain { + fn lower_bound(&self) -> usize { + SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) + } + + fn upper_bound(&self) -> Option { + match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { + (Some(first), Some(second)) => Some(first + second), + _ => None, + } + } +} + + /// Reader adaptor which limits the bytes read from an underlying reader. /// /// This struct is generally created by calling [`take`] on a reader. @@ -2491,12 +2505,6 @@ impl SizeHint for T { } } -impl SizeHint for BufReader { - fn lower_bound(&self) -> usize { - self.buffer().len() - } -} - /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index e43ce4cdb4b8e..7de37c67abebc 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -4,7 +4,7 @@ mod tests; use crate::fmt; -use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; +use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write}; /// A reader which is always at EOF. /// @@ -80,6 +80,12 @@ impl fmt::Debug for Empty { } } +impl SizeHint for Empty { + fn upper_bound(&self) -> Option { + Some(0) + } +} + /// A reader which yields one byte over and over and over and over and over and... /// /// This struct is generally created by calling [`repeat()`]. Please From 389e638c054434c4b9df9427dab29b0f325923ac Mon Sep 17 00:00:00 2001 From: Xavientois Date: Sat, 16 Jan 2021 15:04:26 -0500 Subject: [PATCH 17/67] Add tests for SizeHint implementations --- library/std/src/io/tests.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 03ed8ba74c520..a85dd0d982715 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -204,8 +204,8 @@ fn bufreader_size_hint() { let mut buf_reader = BufReader::new(&testdata[..]); assert_eq!(buf_reader.buffer().len(), 0); - let buffer = buf_reader.fill_buf().unwrap(); - let buffer_length = buffer.len(); + let buffer_length = testdata.len(); + buf_reader.fill_buf().unwrap(); // Check that size hint matches buffer contents let mut buffered_bytes = buf_reader.bytes(); @@ -218,6 +218,33 @@ fn bufreader_size_hint() { assert_eq!(lower_bound, buffer_length - 1); } +#[test] +fn empty_size_hint() { + let size_hint = io::empty().bytes().size_hint(); + assert_eq!(size_hint, (0, Some(0))); +} + +#[test] +fn chain_empty_size_hint() { + let chain = io::empty().chain(io::empty()); + let size_hint = chain.bytes().size_hint(); + assert_eq!(size_hint, (0, Some(0))); +} + +#[test] +fn chain_size_hint() { + let testdata = b"ABCDEFGHIJKL"; + let mut buf_reader_1 = BufReader::new(&testdata[..6]); + let mut buf_reader_2 = BufReader::new(&testdata[6..]); + + buf_reader_1.fill_buf().unwrap(); + buf_reader_2.fill_buf().unwrap(); + + let chain = buf_reader_1.chain(buf_reader_2); + let size_hint = chain.bytes().size_hint(); + assert_eq!(size_hint, (testdata.len(), None)); +} + #[test] fn chain_zero_length_read_is_not_eof() { let a = b"A"; From b837f3a99b8dc767c4a6a3216ad3940f23896932 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Sat, 16 Jan 2021 15:20:40 -0500 Subject: [PATCH 18/67] Remove trailing newline --- library/std/src/io/buffered/bufreader.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index e737a104014f4..839c64ee5c443 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -1,6 +1,8 @@ use crate::cmp; use crate::fmt; -use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE}; +use crate::io::{ + self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE, +}; /// The `BufReader` struct adds buffering to any reader. /// @@ -441,4 +443,3 @@ impl SizeHint for BufReader { self.buffer().len() } } - From 81aba388f16502cbb7b305d64de9ccc95057b339 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Sat, 16 Jan 2021 15:36:59 -0500 Subject: [PATCH 19/67] Add space for proper indentation --- library/std/src/io/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index 7de37c67abebc..e5e5f29b22d09 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -82,7 +82,7 @@ impl fmt::Debug for Empty { impl SizeHint for Empty { fn upper_bound(&self) -> Option { - Some(0) + Some(0) } } From fc9cd4a14be3ea1d5ee29b495045fa51edfc0810 Mon Sep 17 00:00:00 2001 From: Xavientois Date: Sat, 16 Jan 2021 17:48:22 -0500 Subject: [PATCH 20/67] Fix formatting on mod --- library/std/src/io/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 08b258bb816ec..b7ccf9f21efb0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2244,7 +2244,7 @@ impl SizeHint for Chain { SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second) } - fn upper_bound(&self) -> Option { + fn upper_bound(&self) -> Option { match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) { (Some(first), Some(second)) => Some(first + second), _ => None, @@ -2252,7 +2252,6 @@ impl SizeHint for Chain { } } - /// Reader adaptor which limits the bytes read from an underlying reader. /// /// This struct is generally created by calling [`take`] on a reader. From 7674ae1a4e10ab6bafbda57f9fc2175fdf012f5e Mon Sep 17 00:00:00 2001 From: Xavientois Date: Sun, 31 Jan 2021 08:52:57 -0500 Subject: [PATCH 21/67] Fix line length format --- library/std/src/io/util.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index e5e5f29b22d09..f472361f916db 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -4,7 +4,9 @@ mod tests; use crate::fmt; -use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write}; +use crate::io::{ + self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write, +}; /// A reader which is always at EOF. /// From 4cb089bb542f30faa708c65347aacef42c2427cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 Apr 2020 11:15:04 -0700 Subject: [PATCH 22/67] Inherit `#[stable(..)]` annotations in enum variants and fields from its item --- compiler/rustc_passes/src/lib_features.rs | 2 +- compiler/rustc_passes/src/stability.rs | 48 +++++-- .../deprecation/deprecation-in-staged-api.rs | 8 +- .../deprecation-in-staged-api.stderr | 10 +- .../lint/auxiliary/lint_stability_fields.rs | 23 +++- .../lint/lint-stability-fields-deprecated.rs | 11 +- .../lint-stability-fields-deprecated.stderr | 126 +++++++++--------- src/test/ui/lint/lint-stability-fields.rs | 20 ++- src/test/ui/lint/lint-stability-fields.stderr | 86 ++++++------ .../stability-attribute-issue-43027.rs | 9 +- .../stability-attribute-issue-43027.stderr | 8 -- .../stability-attribute-sanity.rs | 5 +- .../stability-attribute-sanity.stderr | 8 +- 13 files changed, 207 insertions(+), 157 deletions(-) delete mode 100644 src/test/ui/stability-attribute/stability-attribute-issue-43027.stderr diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 7c62a234dbaec..02b20e45d000c 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -109,7 +109,7 @@ impl LibFeatureCollector<'tcx> { } fn span_feature_error(&self, span: Span, msg: &str) { - struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg,).emit(); + struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg).emit(); } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index e1d03e3504800..0e142665911da 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -70,6 +70,17 @@ impl InheritConstStability { } } +enum InheritStability { + Yes, + No, +} + +impl InheritStability { + fn yes(&self) -> bool { + matches!(self, InheritStability::Yes) + } +} + // A private tree-walker for producing an Index. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -91,6 +102,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { kind: AnnotationKind, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, + inherit_from_parent: InheritStability, visit_children: F, ) where F: FnOnce(&mut Self), @@ -131,12 +143,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } if self.tcx.features().staged_api { - if let Some(..) = attrs.iter().find(|a| self.tcx.sess.check_name(a, sym::deprecated)) { - self.tcx.sess.span_err( - item_sp, - "`#[deprecated]` cannot be used in staged API; \ - use `#[rustc_deprecated]` instead", - ); + if let Some(a) = attrs.iter().find(|a| self.tcx.sess.check_name(a, sym::deprecated)) { + self.tcx + .sess + .struct_span_err(a.span, "`#[deprecated]` cannot be used in staged API") + .span_label(a.span, "use `#[rustc_deprecated]` instead") + .span_label(item_sp, "") + .emit(); } } else { self.recurse_with_stability_attrs( @@ -185,7 +198,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if kind == AnnotationKind::Prohibited || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated) { - self.tcx.sess.span_err(item_sp, "This stability annotation is useless"); + self.tcx.sess.span_err(item_sp, "this stability annotation is useless"); } debug!("annotate: found {:?}", stab); @@ -202,7 +215,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { { match stab_v.parse::() { Err(_) => { - self.tcx.sess.span_err(item_sp, "Invalid stability version found"); + self.tcx.sess.span_err(item_sp, "invalid stability version found"); break; } Ok(stab_vp) => match dep_v.parse::() { @@ -210,7 +223,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { Ordering::Less => { self.tcx.sess.span_err( item_sp, - "An API can't be stabilized after it is deprecated", + "an API can't be stabilized after it is deprecated", ); break; } @@ -221,7 +234,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if dep_v != "TBD" { self.tcx .sess - .span_err(item_sp, "Invalid deprecation version found"); + .span_err(item_sp, "invalid deprecation version found"); } break; } @@ -237,7 +250,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if stab.is_none() { debug!("annotate: stab not found, parent = {:?}", self.parent_stab); if let Some(stab) = self.parent_stab { - if inherit_deprecation.yes() && stab.level.is_unstable() { + if inherit_deprecation.yes() && stab.level.is_unstable() + || inherit_from_parent.yes() + { self.index.stab_map.insert(hir_id, stab); } } @@ -368,6 +383,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::Yes, |_| {}, ) } @@ -382,6 +398,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { kind, InheritDeprecation::Yes, const_stab_inherit, + InheritStability::No, |v| intravisit::walk_item(v, i), ); self.in_trait_impl = orig_in_trait_impl; @@ -395,6 +412,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::No, |v| { intravisit::walk_trait_item(v, ti); }, @@ -411,6 +429,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { kind, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::No, |v| { intravisit::walk_impl_item(v, ii); }, @@ -425,6 +444,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::Yes, |v| { if let Some(ctor_hir_id) = var.data.ctor_hir_id() { v.annotate( @@ -434,6 +454,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::No, |_| {}, ); } @@ -451,6 +472,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::Yes, |v| { intravisit::walk_struct_field(v, s); }, @@ -465,6 +487,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::No, |v| { intravisit::walk_foreign_item(v, i); }, @@ -479,6 +502,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::No, |_| {}, ); } @@ -499,6 +523,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { kind, InheritDeprecation::No, InheritConstStability::No, + InheritStability::No, |v| { intravisit::walk_generic_param(v, p); }, @@ -669,6 +694,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, + InheritStability::No, |v| intravisit::walk_crate(v, krate), ); } diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.rs b/src/test/ui/deprecation/deprecation-in-staged-api.rs index f667de83b56d4..910bfd1b5e48a 100644 --- a/src/test/ui/deprecation/deprecation-in-staged-api.rs +++ b/src/test/ui/deprecation/deprecation-in-staged-api.rs @@ -1,8 +1,4 @@ -// #[deprecated] cannot be used in staged API - #![feature(staged_api)] - #![stable(feature = "stable_test_feature", since = "1.0.0")] - -#[deprecated] -fn main() { } //~ ERROR `#[deprecated]` cannot be used in staged API +#[deprecated] //~ ERROR `#[deprecated]` cannot be used in staged API +fn main() {} diff --git a/src/test/ui/deprecation/deprecation-in-staged-api.stderr b/src/test/ui/deprecation/deprecation-in-staged-api.stderr index c6881d5a5735f..cf977fa4b7b44 100644 --- a/src/test/ui/deprecation/deprecation-in-staged-api.stderr +++ b/src/test/ui/deprecation/deprecation-in-staged-api.stderr @@ -1,8 +1,10 @@ -error: `#[deprecated]` cannot be used in staged API; use `#[rustc_deprecated]` instead - --> $DIR/deprecation-in-staged-api.rs:8:1 +error: `#[deprecated]` cannot be used in staged API + --> $DIR/deprecation-in-staged-api.rs:3:1 | -LL | fn main() { } - | ^^^^^^^^^^^^^ +LL | #[deprecated] + | ^^^^^^^^^^^^^ use `#[rustc_deprecated]` instead +LL | fn main() {} + | ------------ error: aborting due to previous error diff --git a/src/test/ui/lint/auxiliary/lint_stability_fields.rs b/src/test/ui/lint/auxiliary/lint_stability_fields.rs index 0efe7686ef76a..3cbb48c4a6be0 100644 --- a/src/test/ui/lint/auxiliary/lint_stability_fields.rs +++ b/src/test/ui/lint/auxiliary/lint_stability_fields.rs @@ -3,20 +3,35 @@ #[stable(feature = "rust1", since = "1.0.0")] pub struct Stable { - #[stable(feature = "rust1", since = "1.0.0")] - pub inherit: u8, // it's a lie (stable doesn't inherit) + pub inherit: u8, #[unstable(feature = "unstable_test_feature", issue = "none")] pub override1: u8, #[rustc_deprecated(since = "1.0.0", reason = "text")] #[unstable(feature = "unstable_test_feature", issue = "none")] pub override2: u8, + #[stable(feature = "rust2", since = "2.0.0")] + pub override3: u8, } #[stable(feature = "rust1", since = "1.0.0")] -pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8, +pub struct Stable2(#[stable(feature = "rust2", since = "2.0.0")] pub u8, #[unstable(feature = "unstable_test_feature", issue = "none")] pub u8, #[unstable(feature = "unstable_test_feature", issue = "none")] - #[rustc_deprecated(since = "1.0.0", reason = "text")] pub u8); + #[rustc_deprecated(since = "1.0.0", reason = "text")] pub u8, + pub u8); + +#[stable(feature = "rust1", since = "1.0.0")] +pub enum Stable3 { + Inherit(u8), + InheritOverride(#[stable(feature = "rust2", since = "2.0.0")] u8), + #[stable(feature = "rust2", since = "2.0.0")] + Override1, + #[unstable(feature = "unstable_test_feature", issue = "none")] + Override2, + #[rustc_deprecated(since = "1.0.0", reason = "text")] + #[unstable(feature = "unstable_test_feature", issue = "none")] + Override3, +} #[unstable(feature = "unstable_test_feature", issue = "none")] pub struct Unstable { diff --git a/src/test/ui/lint/lint-stability-fields-deprecated.rs b/src/test/ui/lint/lint-stability-fields-deprecated.rs index 14c6383806fb8..2024cf15ab0a1 100644 --- a/src/test/ui/lint/lint-stability-fields-deprecated.rs +++ b/src/test/ui/lint/lint-stability-fields-deprecated.rs @@ -17,33 +17,38 @@ mod cross_crate { override1: 2, override2: 3, //~^ ERROR use of deprecated field + override3: 4, }; let _ = x.inherit; let _ = x.override1; let _ = x.override2; //~^ ERROR use of deprecated field + let _ = x.override3; let Stable { inherit: _, override1: _, - override2: _ + override2: _, //~^ ERROR use of deprecated field + override3: _, } = x; // all fine let Stable { .. } = x; - let x = Stable2(1, 2, 3); + let x = Stable2(1, 2, 3, 4); let _ = x.0; let _ = x.1; let _ = x.2; //~^ ERROR use of deprecated field + let _ = x.3; let Stable2(_, _, + _, + //~^ ERROR use of deprecated field _) - //~^ ERROR use of deprecated field = x; // all fine let Stable2(..) = x; diff --git a/src/test/ui/lint/lint-stability-fields-deprecated.stderr b/src/test/ui/lint/lint-stability-fields-deprecated.stderr index ec786786023b9..151b3e59b9130 100644 --- a/src/test/ui/lint/lint-stability-fields-deprecated.stderr +++ b/src/test/ui/lint/lint-stability-fields-deprecated.stderr @@ -1,5 +1,5 @@ error: use of deprecated struct `cross_crate::lint_stability_fields::Deprecated`: text - --> $DIR/lint-stability-fields-deprecated.rs:94:17 + --> $DIR/lint-stability-fields-deprecated.rs:99:17 | LL | let x = Deprecated { | ^^^^^^^^^^ @@ -11,67 +11,67 @@ LL | #![deny(deprecated)] | ^^^^^^^^^^ error: use of deprecated struct `cross_crate::lint_stability_fields::Deprecated`: text - --> $DIR/lint-stability-fields-deprecated.rs:111:13 + --> $DIR/lint-stability-fields-deprecated.rs:116:13 | LL | let Deprecated { | ^^^^^^^^^^ error: use of deprecated struct `cross_crate::lint_stability_fields::Deprecated`: text - --> $DIR/lint-stability-fields-deprecated.rs:121:13 + --> $DIR/lint-stability-fields-deprecated.rs:126:13 | LL | let Deprecated | ^^^^^^^^^^ error: use of deprecated struct `cross_crate::lint_stability_fields::Deprecated2`: text - --> $DIR/lint-stability-fields-deprecated.rs:126:17 + --> $DIR/lint-stability-fields-deprecated.rs:131:17 | LL | let x = Deprecated2(1, 2, 3); | ^^^^^^^^^^^ error: use of deprecated struct `cross_crate::lint_stability_fields::Deprecated2`: text - --> $DIR/lint-stability-fields-deprecated.rs:136:13 + --> $DIR/lint-stability-fields-deprecated.rs:141:13 | LL | let Deprecated2 | ^^^^^^^^^^^ error: use of deprecated struct `cross_crate::lint_stability_fields::Deprecated2`: text - --> $DIR/lint-stability-fields-deprecated.rs:145:13 + --> $DIR/lint-stability-fields-deprecated.rs:150:13 | LL | let Deprecated2 | ^^^^^^^^^^^ error: use of deprecated struct `this_crate::Deprecated`: text - --> $DIR/lint-stability-fields-deprecated.rs:281:17 + --> $DIR/lint-stability-fields-deprecated.rs:286:17 | LL | let x = Deprecated { | ^^^^^^^^^^ error: use of deprecated struct `this_crate::Deprecated`: text - --> $DIR/lint-stability-fields-deprecated.rs:298:13 + --> $DIR/lint-stability-fields-deprecated.rs:303:13 | LL | let Deprecated { | ^^^^^^^^^^ error: use of deprecated struct `this_crate::Deprecated`: text - --> $DIR/lint-stability-fields-deprecated.rs:308:13 + --> $DIR/lint-stability-fields-deprecated.rs:313:13 | LL | let Deprecated | ^^^^^^^^^^ error: use of deprecated tuple struct `this_crate::Deprecated2`: text - --> $DIR/lint-stability-fields-deprecated.rs:313:17 + --> $DIR/lint-stability-fields-deprecated.rs:318:17 | LL | let x = Deprecated2(1, 2, 3); | ^^^^^^^^^^^ error: use of deprecated tuple struct `this_crate::Deprecated2`: text - --> $DIR/lint-stability-fields-deprecated.rs:323:13 + --> $DIR/lint-stability-fields-deprecated.rs:328:13 | LL | let Deprecated2 | ^^^^^^^^^^^ error: use of deprecated tuple struct `this_crate::Deprecated2`: text - --> $DIR/lint-stability-fields-deprecated.rs:332:13 + --> $DIR/lint-stability-fields-deprecated.rs:337:13 | LL | let Deprecated2 | ^^^^^^^^^^^ @@ -83,295 +83,295 @@ LL | override2: 3, | ^^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Stable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:24:17 + --> $DIR/lint-stability-fields-deprecated.rs:25:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Stable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:30:13 + --> $DIR/lint-stability-fields-deprecated.rs:32:13 | -LL | override2: _ +LL | override2: _, | ^^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Stable2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:40:17 + --> $DIR/lint-stability-fields-deprecated.rs:43:17 | LL | let _ = x.2; | ^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Stable2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:45:20 + --> $DIR/lint-stability-fields-deprecated.rs:49:20 | -LL | _) +LL | _, | ^ error: use of deprecated field `cross_crate::lint_stability_fields::Unstable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:55:13 + --> $DIR/lint-stability-fields-deprecated.rs:60:13 | LL | override2: 3, | ^^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Unstable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:61:17 + --> $DIR/lint-stability-fields-deprecated.rs:66:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Unstable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:67:13 + --> $DIR/lint-stability-fields-deprecated.rs:72:13 | LL | override2: _ | ^^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Unstable2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:80:17 + --> $DIR/lint-stability-fields-deprecated.rs:85:17 | LL | let _ = x.2; | ^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Unstable2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:86:14 + --> $DIR/lint-stability-fields-deprecated.rs:91:14 | LL | _) | ^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::inherit`: text - --> $DIR/lint-stability-fields-deprecated.rs:96:13 + --> $DIR/lint-stability-fields-deprecated.rs:101:13 | LL | inherit: 1, | ^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::override1`: text - --> $DIR/lint-stability-fields-deprecated.rs:98:13 + --> $DIR/lint-stability-fields-deprecated.rs:103:13 | LL | override1: 2, | ^^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:100:13 + --> $DIR/lint-stability-fields-deprecated.rs:105:13 | LL | override2: 3, | ^^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::inherit`: text - --> $DIR/lint-stability-fields-deprecated.rs:104:17 + --> $DIR/lint-stability-fields-deprecated.rs:109:17 | LL | let _ = x.inherit; | ^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::override1`: text - --> $DIR/lint-stability-fields-deprecated.rs:106:17 + --> $DIR/lint-stability-fields-deprecated.rs:111:17 | LL | let _ = x.override1; | ^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:108:17 + --> $DIR/lint-stability-fields-deprecated.rs:113:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::inherit`: text - --> $DIR/lint-stability-fields-deprecated.rs:113:13 + --> $DIR/lint-stability-fields-deprecated.rs:118:13 | LL | inherit: _, | ^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::override1`: text - --> $DIR/lint-stability-fields-deprecated.rs:115:13 + --> $DIR/lint-stability-fields-deprecated.rs:120:13 | LL | override1: _, | ^^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:117:13 + --> $DIR/lint-stability-fields-deprecated.rs:122:13 | LL | override2: _ | ^^^^^^^^^^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated2::0`: text - --> $DIR/lint-stability-fields-deprecated.rs:129:17 + --> $DIR/lint-stability-fields-deprecated.rs:134:17 | LL | let _ = x.0; | ^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated2::1`: text - --> $DIR/lint-stability-fields-deprecated.rs:131:17 + --> $DIR/lint-stability-fields-deprecated.rs:136:17 | LL | let _ = x.1; | ^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:133:17 + --> $DIR/lint-stability-fields-deprecated.rs:138:17 | LL | let _ = x.2; | ^^^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated2::0`: text - --> $DIR/lint-stability-fields-deprecated.rs:138:14 + --> $DIR/lint-stability-fields-deprecated.rs:143:14 | LL | (_, | ^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated2::1`: text - --> $DIR/lint-stability-fields-deprecated.rs:140:14 + --> $DIR/lint-stability-fields-deprecated.rs:145:14 | LL | _, | ^ error: use of deprecated field `cross_crate::lint_stability_fields::Deprecated2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:142:14 + --> $DIR/lint-stability-fields-deprecated.rs:147:14 | LL | _) | ^ error: use of deprecated field `this_crate::Stable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:205:13 + --> $DIR/lint-stability-fields-deprecated.rs:210:13 | LL | override2: 3, | ^^^^^^^^^^^^ error: use of deprecated field `this_crate::Stable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:211:17 + --> $DIR/lint-stability-fields-deprecated.rs:216:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ error: use of deprecated field `this_crate::Stable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:217:13 + --> $DIR/lint-stability-fields-deprecated.rs:222:13 | LL | override2: _ | ^^^^^^^^^^^^ error: use of deprecated field `this_crate::Stable2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:227:17 + --> $DIR/lint-stability-fields-deprecated.rs:232:17 | LL | let _ = x.2; | ^^^ error: use of deprecated field `this_crate::Stable2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:232:20 + --> $DIR/lint-stability-fields-deprecated.rs:237:20 | LL | _) | ^ error: use of deprecated field `this_crate::Unstable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:242:13 + --> $DIR/lint-stability-fields-deprecated.rs:247:13 | LL | override2: 3, | ^^^^^^^^^^^^ error: use of deprecated field `this_crate::Unstable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:248:17 + --> $DIR/lint-stability-fields-deprecated.rs:253:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ error: use of deprecated field `this_crate::Unstable::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:254:13 + --> $DIR/lint-stability-fields-deprecated.rs:259:13 | LL | override2: _ | ^^^^^^^^^^^^ error: use of deprecated field `this_crate::Unstable2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:267:17 + --> $DIR/lint-stability-fields-deprecated.rs:272:17 | LL | let _ = x.2; | ^^^ error: use of deprecated field `this_crate::Unstable2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:273:14 + --> $DIR/lint-stability-fields-deprecated.rs:278:14 | LL | _) | ^ error: use of deprecated field `this_crate::Deprecated::inherit`: text - --> $DIR/lint-stability-fields-deprecated.rs:283:13 + --> $DIR/lint-stability-fields-deprecated.rs:288:13 | LL | inherit: 1, | ^^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated::override1`: text - --> $DIR/lint-stability-fields-deprecated.rs:285:13 + --> $DIR/lint-stability-fields-deprecated.rs:290:13 | LL | override1: 2, | ^^^^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:287:13 + --> $DIR/lint-stability-fields-deprecated.rs:292:13 | LL | override2: 3, | ^^^^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated::inherit`: text - --> $DIR/lint-stability-fields-deprecated.rs:291:17 + --> $DIR/lint-stability-fields-deprecated.rs:296:17 | LL | let _ = x.inherit; | ^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated::override1`: text - --> $DIR/lint-stability-fields-deprecated.rs:293:17 + --> $DIR/lint-stability-fields-deprecated.rs:298:17 | LL | let _ = x.override1; | ^^^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:295:17 + --> $DIR/lint-stability-fields-deprecated.rs:300:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated::inherit`: text - --> $DIR/lint-stability-fields-deprecated.rs:300:13 + --> $DIR/lint-stability-fields-deprecated.rs:305:13 | LL | inherit: _, | ^^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated::override1`: text - --> $DIR/lint-stability-fields-deprecated.rs:302:13 + --> $DIR/lint-stability-fields-deprecated.rs:307:13 | LL | override1: _, | ^^^^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated::override2`: text - --> $DIR/lint-stability-fields-deprecated.rs:304:13 + --> $DIR/lint-stability-fields-deprecated.rs:309:13 | LL | override2: _ | ^^^^^^^^^^^^ error: use of deprecated field `this_crate::Deprecated2::0`: text - --> $DIR/lint-stability-fields-deprecated.rs:316:17 + --> $DIR/lint-stability-fields-deprecated.rs:321:17 | LL | let _ = x.0; | ^^^ error: use of deprecated field `this_crate::Deprecated2::1`: text - --> $DIR/lint-stability-fields-deprecated.rs:318:17 + --> $DIR/lint-stability-fields-deprecated.rs:323:17 | LL | let _ = x.1; | ^^^ error: use of deprecated field `this_crate::Deprecated2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:320:17 + --> $DIR/lint-stability-fields-deprecated.rs:325:17 | LL | let _ = x.2; | ^^^ error: use of deprecated field `this_crate::Deprecated2::0`: text - --> $DIR/lint-stability-fields-deprecated.rs:325:14 + --> $DIR/lint-stability-fields-deprecated.rs:330:14 | LL | (_, | ^ error: use of deprecated field `this_crate::Deprecated2::1`: text - --> $DIR/lint-stability-fields-deprecated.rs:327:14 + --> $DIR/lint-stability-fields-deprecated.rs:332:14 | LL | _, | ^ error: use of deprecated field `this_crate::Deprecated2::2`: text - --> $DIR/lint-stability-fields-deprecated.rs:329:14 + --> $DIR/lint-stability-fields-deprecated.rs:334:14 | LL | _) | ^ diff --git a/src/test/ui/lint/lint-stability-fields.rs b/src/test/ui/lint/lint-stability-fields.rs index c5de5748aa300..4083648984867 100644 --- a/src/test/ui/lint/lint-stability-fields.rs +++ b/src/test/ui/lint/lint-stability-fields.rs @@ -20,29 +20,34 @@ mod cross_crate { inherit: 1, override1: 2, //~ ERROR use of unstable override2: 3, //~ ERROR use of unstable + override3: 4, }; let _ = x.inherit; let _ = x.override1; //~ ERROR use of unstable let _ = x.override2; //~ ERROR use of unstable + let _ = x.override3; let Stable { inherit: _, override1: _, //~ ERROR use of unstable - override2: _ //~ ERROR use of unstable + override2: _, //~ ERROR use of unstable + override3: _ } = x; // all fine let Stable { .. } = x; - let x = Stable2(1, 2, 3); + let x = Stable2(1, 2, 3, 4); let _ = x.0; let _ = x.1; //~ ERROR use of unstable let _ = x.2; //~ ERROR use of unstable + let _ = x.3; let Stable2(_, _, //~ ERROR use of unstable - _) //~ ERROR use of unstable + _, //~ ERROR use of unstable + _) = x; // all fine let Stable2(..) = x; @@ -133,11 +138,13 @@ mod this_crate { #[rustc_deprecated(since = "1.0.0", reason = "text")] #[unstable(feature = "unstable_test_feature", issue = "none")] override2: u8, + #[stable(feature = "rust2", since = "2.0.0")] + override3: u8, } #[stable(feature = "rust1", since = "1.0.0")] struct Stable2(u8, - #[stable(feature = "rust1", since = "1.0.0")] u8, + #[stable(feature = "rust2", since = "2.0.0")] u8, #[unstable(feature = "unstable_test_feature", issue = "none")] #[rustc_deprecated(since = "1.0.0", reason = "text")] u8); @@ -178,16 +185,19 @@ mod this_crate { inherit: 1, override1: 2, override2: 3, + override3: 4, }; let _ = x.inherit; let _ = x.override1; let _ = x.override2; + let _ = x.override3; let Stable { inherit: _, override1: _, - override2: _ + override2: _, + override3: _ } = x; // all fine let Stable { .. } = x; diff --git a/src/test/ui/lint/lint-stability-fields.stderr b/src/test/ui/lint/lint-stability-fields.stderr index b6a08186b5fb8..3d2e73c1e8e92 100644 --- a/src/test/ui/lint/lint-stability-fields.stderr +++ b/src/test/ui/lint/lint-stability-fields.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:51:17 + --> $DIR/lint-stability-fields.rs:56:17 | LL | let x = Unstable { | ^^^^^^^^ @@ -7,7 +7,7 @@ LL | let x = Unstable { = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:61:13 + --> $DIR/lint-stability-fields.rs:66:13 | LL | let Unstable { | ^^^^^^^^ @@ -15,7 +15,7 @@ LL | let Unstable { = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:67:13 + --> $DIR/lint-stability-fields.rs:72:13 | LL | let Unstable | ^^^^^^^^ @@ -23,7 +23,7 @@ LL | let Unstable = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:72:17 + --> $DIR/lint-stability-fields.rs:77:17 | LL | let x = reexport::Unstable2(1, 2, 3); | ^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | let x = reexport::Unstable2(1, 2, 3); = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:74:17 + --> $DIR/lint-stability-fields.rs:79:17 | LL | let x = Unstable2(1, 2, 3); | ^^^^^^^^^ @@ -39,7 +39,7 @@ LL | let x = Unstable2(1, 2, 3); = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:80:13 + --> $DIR/lint-stability-fields.rs:85:13 | LL | let Unstable2 | ^^^^^^^^^ @@ -47,7 +47,7 @@ LL | let Unstable2 = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:85:13 + --> $DIR/lint-stability-fields.rs:90:13 | LL | let Unstable2 | ^^^^^^^^^ @@ -55,7 +55,7 @@ LL | let Unstable2 = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:90:17 + --> $DIR/lint-stability-fields.rs:95:17 | LL | let x = Deprecated { | ^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | let x = Deprecated { = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:100:13 + --> $DIR/lint-stability-fields.rs:105:13 | LL | let Deprecated { | ^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | let Deprecated { = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:106:13 + --> $DIR/lint-stability-fields.rs:111:13 | LL | let Deprecated | ^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | let Deprecated = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:110:17 + --> $DIR/lint-stability-fields.rs:115:17 | LL | let x = Deprecated2(1, 2, 3); | ^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | let x = Deprecated2(1, 2, 3); = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:116:13 + --> $DIR/lint-stability-fields.rs:121:13 | LL | let Deprecated2 | ^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | let Deprecated2 = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:121:13 + --> $DIR/lint-stability-fields.rs:126:13 | LL | let Deprecated2 | ^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | override2: 3, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:26:17 + --> $DIR/lint-stability-fields.rs:27:17 | LL | let _ = x.override1; | ^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | let _ = x.override1; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:27:17 + --> $DIR/lint-stability-fields.rs:28:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | let _ = x.override2; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:31:13 + --> $DIR/lint-stability-fields.rs:33:13 | LL | override1: _, | ^^^^^^^^^^^^ @@ -143,15 +143,15 @@ LL | override1: _, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:32:13 + --> $DIR/lint-stability-fields.rs:34:13 | -LL | override2: _ +LL | override2: _, | ^^^^^^^^^^^^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:40:17 + --> $DIR/lint-stability-fields.rs:43:17 | LL | let _ = x.1; | ^^^ @@ -159,7 +159,7 @@ LL | let _ = x.1; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:41:17 + --> $DIR/lint-stability-fields.rs:44:17 | LL | let _ = x.2; | ^^^ @@ -167,7 +167,7 @@ LL | let _ = x.2; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:44:20 + --> $DIR/lint-stability-fields.rs:48:20 | LL | _, | ^ @@ -175,15 +175,15 @@ LL | _, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:45:20 + --> $DIR/lint-stability-fields.rs:49:20 | -LL | _) +LL | _, | ^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:52:13 + --> $DIR/lint-stability-fields.rs:57:13 | LL | inherit: 1, | ^^^^^^^^^^ @@ -191,7 +191,7 @@ LL | inherit: 1, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:54:13 + --> $DIR/lint-stability-fields.rs:59:13 | LL | override2: 3, | ^^^^^^^^^^^^ @@ -199,7 +199,7 @@ LL | override2: 3, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:57:17 + --> $DIR/lint-stability-fields.rs:62:17 | LL | let _ = x.inherit; | ^^^^^^^^^ @@ -207,7 +207,7 @@ LL | let _ = x.inherit; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:59:17 + --> $DIR/lint-stability-fields.rs:64:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ @@ -215,7 +215,7 @@ LL | let _ = x.override2; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:62:13 + --> $DIR/lint-stability-fields.rs:67:13 | LL | inherit: _, | ^^^^^^^^^^ @@ -223,7 +223,7 @@ LL | inherit: _, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:64:13 + --> $DIR/lint-stability-fields.rs:69:13 | LL | override2: _ | ^^^^^^^^^^^^ @@ -231,7 +231,7 @@ LL | override2: _ = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:76:17 + --> $DIR/lint-stability-fields.rs:81:17 | LL | let _ = x.0; | ^^^ @@ -239,7 +239,7 @@ LL | let _ = x.0; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:78:17 + --> $DIR/lint-stability-fields.rs:83:17 | LL | let _ = x.2; | ^^^ @@ -247,7 +247,7 @@ LL | let _ = x.2; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:81:14 + --> $DIR/lint-stability-fields.rs:86:14 | LL | (_, | ^ @@ -255,7 +255,7 @@ LL | (_, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:83:14 + --> $DIR/lint-stability-fields.rs:88:14 | LL | _) | ^ @@ -263,7 +263,7 @@ LL | _) = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:91:13 + --> $DIR/lint-stability-fields.rs:96:13 | LL | inherit: 1, | ^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | inherit: 1, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:93:13 + --> $DIR/lint-stability-fields.rs:98:13 | LL | override2: 3, | ^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | override2: 3, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:96:17 + --> $DIR/lint-stability-fields.rs:101:17 | LL | let _ = x.inherit; | ^^^^^^^^^ @@ -287,7 +287,7 @@ LL | let _ = x.inherit; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:98:17 + --> $DIR/lint-stability-fields.rs:103:17 | LL | let _ = x.override2; | ^^^^^^^^^^^ @@ -295,7 +295,7 @@ LL | let _ = x.override2; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:101:13 + --> $DIR/lint-stability-fields.rs:106:13 | LL | inherit: _, | ^^^^^^^^^^ @@ -303,7 +303,7 @@ LL | inherit: _, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:103:13 + --> $DIR/lint-stability-fields.rs:108:13 | LL | override2: _ | ^^^^^^^^^^^^ @@ -311,7 +311,7 @@ LL | override2: _ = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:112:17 + --> $DIR/lint-stability-fields.rs:117:17 | LL | let _ = x.0; | ^^^ @@ -319,7 +319,7 @@ LL | let _ = x.0; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:114:17 + --> $DIR/lint-stability-fields.rs:119:17 | LL | let _ = x.2; | ^^^ @@ -327,7 +327,7 @@ LL | let _ = x.2; = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:117:14 + --> $DIR/lint-stability-fields.rs:122:14 | LL | (_, | ^ @@ -335,7 +335,7 @@ LL | (_, = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'unstable_test_feature' - --> $DIR/lint-stability-fields.rs:119:14 + --> $DIR/lint-stability-fields.rs:124:14 | LL | _) | ^ diff --git a/src/test/ui/stability-attribute/stability-attribute-issue-43027.rs b/src/test/ui/stability-attribute/stability-attribute-issue-43027.rs index 0b243bb52119b..3f4fdfd0180ed 100644 --- a/src/test/ui/stability-attribute/stability-attribute-issue-43027.rs +++ b/src/test/ui/stability-attribute/stability-attribute-issue-43027.rs @@ -1,10 +1,15 @@ +// check-pass #![feature(staged_api)] #![stable(feature = "test", since = "0")] #[stable(feature = "test", since = "0")] -pub struct Reverse(pub T); //~ ERROR field has missing stability attribute +pub struct A(pub T); + +#[stable(feature = "test", since = "0")] +pub struct B(#[stable(feature = "test", since = "0")] pub T); fn main() { // Make sure the field is used to fill the stability cache - Reverse(0).0; + A(0).0; + B(0).0; } diff --git a/src/test/ui/stability-attribute/stability-attribute-issue-43027.stderr b/src/test/ui/stability-attribute/stability-attribute-issue-43027.stderr deleted file mode 100644 index 280c72acccb18..0000000000000 --- a/src/test/ui/stability-attribute/stability-attribute-issue-43027.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: field has missing stability attribute - --> $DIR/stability-attribute-issue-43027.rs:5:23 - | -LL | pub struct Reverse(pub T); - | ^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs index 0c40f8ae1c67e..1cc31d8ec187d 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs @@ -62,12 +62,11 @@ fn multiple3() { } #[rustc_deprecated(since = "b", reason = "text")] //~ ERROR multiple deprecated attributes #[rustc_const_unstable(feature = "c", issue = "none")] #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels -pub const fn multiple4() { } -//~^ ERROR Invalid stability version found +pub const fn multiple4() { } //~ ERROR invalid stability version found #[stable(feature = "a", since = "1.0.0")] #[rustc_deprecated(since = "invalid", reason = "text")] -fn invalid_deprecation_version() {} //~ ERROR Invalid deprecation version found +fn invalid_deprecation_version() {} //~ ERROR invalid deprecation version found #[rustc_deprecated(since = "a", reason = "text")] fn deprecated_without_unstable_or_stable() { } diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index 674139f4afcce..07e3da73c60c7 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -96,20 +96,20 @@ error[E0544]: multiple stability levels LL | #[rustc_const_unstable(feature = "d", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Invalid stability version found +error: invalid stability version found --> $DIR/stability-attribute-sanity.rs:65:1 | LL | pub const fn multiple4() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: Invalid deprecation version found - --> $DIR/stability-attribute-sanity.rs:70:1 +error: invalid deprecation version found + --> $DIR/stability-attribute-sanity.rs:69:1 | LL | fn invalid_deprecation_version() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute - --> $DIR/stability-attribute-sanity.rs:72:1 + --> $DIR/stability-attribute-sanity.rs:71:1 | LL | #[rustc_deprecated(since = "a", reason = "text")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 19806e451476d9a97175d2ca0c095545e8894421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 10 Feb 2021 21:35:27 -0800 Subject: [PATCH 23/67] Tweak stability attribute diagnostic output --- compiler/rustc_attr/src/builtin.rs | 27 ++++++++------ compiler/rustc_expand/src/base.rs | 9 +++-- compiler/rustc_passes/src/stability.rs | 36 ++++++++++--------- .../stability-attribute-sanity.rs | 8 ++--- .../stability-attribute-sanity.stderr | 14 +++++--- 5 files changed, 55 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index aca3fbbca1357..c701441e9e5bc 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -176,7 +176,7 @@ pub fn find_stability( sess: &Session, attrs: &[Attribute], item_sp: Span, -) -> (Option, Option) { +) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) { find_stability_generic(sess, attrs.iter(), item_sp) } @@ -184,15 +184,16 @@ fn find_stability_generic<'a, I>( sess: &Session, attrs_iter: I, item_sp: Span, -) -> (Option, Option) +) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) where I: Iterator, { use StabilityLevel::*; - let mut stab: Option = None; - let mut const_stab: Option = None; + let mut stab: Option<(Stability, Span)> = None; + let mut const_stab: Option<(ConstStability, Span)> = None; let mut promotable = false; + let diagnostic = &sess.parse_sess.span_diagnostic; 'outer: for attr in attrs_iter { @@ -356,10 +357,12 @@ where } let level = Unstable { reason, issue: issue_num, is_soft }; if sym::unstable == meta_name { - stab = Some(Stability { level, feature }); + stab = Some((Stability { level, feature }, attr.span)); } else { - const_stab = - Some(ConstStability { level, feature, promotable: false }); + const_stab = Some(( + ConstStability { level, feature, promotable: false }, + attr.span, + )); } } (None, _, _) => { @@ -432,10 +435,12 @@ where (Some(feature), Some(since)) => { let level = Stable { since }; if sym::stable == meta_name { - stab = Some(Stability { level, feature }); + stab = Some((Stability { level, feature }, attr.span)); } else { - const_stab = - Some(ConstStability { level, feature, promotable: false }); + const_stab = Some(( + ConstStability { level, feature, promotable: false }, + attr.span, + )); } } (None, _) => { @@ -455,7 +460,7 @@ where // Merge the const-unstable info into the stability info if promotable { - if let Some(ref mut stab) = const_stab { + if let Some((ref mut stab, _)) = const_stab { stab.promotable = promotable; } else { struct_span_err!( diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index e3dc793a7fac4..bd93e34af680b 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -770,10 +770,13 @@ impl SyntaxExtension { .find_by_name(attrs, sym::rustc_builtin_macro) .map(|a| a.value_str().unwrap_or(name)); let (stability, const_stability) = attr::find_stability(&sess, attrs, span); - if const_stability.is_some() { + if let Some((_, sp)) = const_stability { sess.parse_sess .span_diagnostic - .span_err(span, "macros cannot have const stability attributes"); + .struct_span_err(sp, "macros cannot have const stability attributes") + .span_label(sp, "invalid stability attribute") + .span_label(span, "in this macro") + .emit(); } SyntaxExtension { @@ -782,7 +785,7 @@ impl SyntaxExtension { allow_internal_unstable, allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe), local_inner_macros, - stability, + stability: stability.map(|(s, _)| s), deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d), helper_attrs, edition, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 0e142665911da..d698512a648aa 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -163,7 +163,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp); - let const_stab = const_stab.map(|const_stab| { + let const_stab = const_stab.map(|(const_stab, _)| { let const_stab = self.tcx.intern_const_stability(const_stab); self.index.const_stab_map.insert(hir_id, const_stab); const_stab @@ -193,12 +193,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - let stab = stab.map(|stab| { + let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. if kind == AnnotationKind::Prohibited || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated) { - self.tcx.sess.span_err(item_sp, "this stability annotation is useless"); + self.tcx.sess.struct_span_err(span,"this stability annotation is useless") + .span_label(span, "useless stability annotation") + .span_label(item_sp, "the stability attribute annotates this item") + .emit(); } debug!("annotate: found {:?}", stab); @@ -215,16 +218,19 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { { match stab_v.parse::() { Err(_) => { - self.tcx.sess.span_err(item_sp, "invalid stability version found"); + self.tcx.sess.struct_span_err(span, "invalid stability version found") + .span_label(span, "invalid stability version") + .span_label(item_sp, "the stability attribute annotates this item") + .emit(); break; } Ok(stab_vp) => match dep_v.parse::() { Ok(dep_vp) => match dep_vp.cmp(&stab_vp) { Ordering::Less => { - self.tcx.sess.span_err( - item_sp, - "an API can't be stabilized after it is deprecated", - ); + self.tcx.sess.struct_span_err(span, "an API can't be stabilized after it is deprecated") + .span_label(span, "invalid version") + .span_label(item_sp, "the stability attribute annotates this item") + .emit(); break; } Ordering::Equal => continue, @@ -232,9 +238,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { }, Err(_) => { if dep_v != "TBD" { - self.tcx - .sess - .span_err(item_sp, "invalid deprecation version found"); + self.tcx.sess.struct_span_err(span, "invalid deprecation version found") + .span_label(span, "invalid deprecation version") + .span_label(item_sp, "the stability attribute annotates this item") + .emit(); } break; } @@ -756,18 +763,13 @@ impl Visitor<'tcx> for Checker<'tcx> { // error if all involved types and traits are stable, because // it will have no effect. // See: https://github.com/rust-lang/rust/issues/55436 - if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) = + if let (Some((Stability { level: attr::Unstable { .. }, .. }, span)), _) = attr::find_stability(&self.tcx.sess, &item.attrs, item.span) { let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true }; c.visit_ty(self_ty); c.visit_trait_ref(t); if c.fully_stable { - let span = item - .attrs - .iter() - .find(|a| a.has_name(sym::unstable)) - .map_or(item.span, |a| a.span); self.tcx.struct_span_lint_hir( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id, diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs index 1cc31d8ec187d..9f8ecc2628126 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs @@ -57,16 +57,16 @@ fn multiple2() { } #[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544] fn multiple3() { } -#[stable(feature = "a", since = "b")] +#[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found #[rustc_deprecated(since = "b", reason = "text")] #[rustc_deprecated(since = "b", reason = "text")] //~ ERROR multiple deprecated attributes #[rustc_const_unstable(feature = "c", issue = "none")] #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels -pub const fn multiple4() { } //~ ERROR invalid stability version found +pub const fn multiple4() { } -#[stable(feature = "a", since = "1.0.0")] +#[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found #[rustc_deprecated(since = "invalid", reason = "text")] -fn invalid_deprecation_version() {} //~ ERROR invalid deprecation version found +fn invalid_deprecation_version() {} #[rustc_deprecated(since = "a", reason = "text")] fn deprecated_without_unstable_or_stable() { } diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr index 07e3da73c60c7..bde35cca4a289 100644 --- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr @@ -97,16 +97,22 @@ LL | #[rustc_const_unstable(feature = "d", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid stability version found - --> $DIR/stability-attribute-sanity.rs:65:1 + --> $DIR/stability-attribute-sanity.rs:60:1 | +LL | #[stable(feature = "a", since = "b")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid stability version +... LL | pub const fn multiple4() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ---------------------------- the stability attribute annotates this item error: invalid deprecation version found - --> $DIR/stability-attribute-sanity.rs:69:1 + --> $DIR/stability-attribute-sanity.rs:67:1 | +LL | #[stable(feature = "a", since = "1.0.0")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid deprecation version +LL | #[rustc_deprecated(since = "invalid", reason = "text")] LL | fn invalid_deprecation_version() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------------------------------- the stability attribute annotates this item error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute --> $DIR/stability-attribute-sanity.rs:71:1 From 7b021aacb57d7a120f280302358d7bdd04a67bbc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 29 Jan 2021 00:59:20 +0300 Subject: [PATCH 24/67] resolve: Reduce scope of `pub_use_of_private_extern_crate` deprecation lint --- compiler/rustc_resolve/src/imports.rs | 32 +++++++++------ src/test/rustdoc/extern-links.rs | 2 +- src/test/rustdoc/issue-28927.rs | 2 +- .../ui/pub/pub-reexport-priv-extern-crate.rs | 8 +--- .../pub/pub-reexport-priv-extern-crate.stderr | 39 +++++++++++-------- 5 files changed, 47 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index bd0296751a535..61f4c00a4ca42 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -156,6 +156,21 @@ impl<'a> NameResolution<'a> { } } +// Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` +// are permitted for backward-compatibility under a deprecation lint. +fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBinding<'_>) -> bool { + match (&import.kind, &binding.kind) { + ( + ImportKind::Single { .. }, + NameBindingKind::Import { + import: Import { kind: ImportKind::ExternCrate { .. }, .. }, + .. + }, + ) => import.vis.get() == ty::Visibility::Public, + _ => false, + } +} + impl<'a> Resolver<'a> { crate fn resolve_ident_in_module_unadjusted( &mut self, @@ -263,10 +278,7 @@ impl<'a> Resolver<'a> { return Err((Determined, Weak::No)); } } - // `extern crate` are always usable for backwards compatibility, see issue #37020, - // remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`. - let usable = this.is_accessible_from(binding.vis, parent_scope.module) - || binding.is_extern_crate(); + let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; @@ -309,10 +321,7 @@ impl<'a> Resolver<'a> { } } - if !(self.is_accessible_from(binding.vis, parent_scope.module) || - // Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE` - (self.last_import_segment && binding.is_extern_crate())) - { + if !self.is_accessible_from(binding.vis, parent_scope.module) { self.privacy_errors.push(PrivacyError { ident, binding, @@ -455,9 +464,8 @@ impl<'a> Resolver<'a> { binding: &'a NameBinding<'a>, import: &'a Import<'a>, ) -> &'a NameBinding<'a> { - let vis = if binding.vis.is_at_least(import.vis.get(), self) || - // cf. `PUB_USE_OF_PRIVATE_EXTERN_CRATE` - !import.is_glob() && binding.is_extern_crate() + let vis = if binding.vis.is_at_least(import.vis.get(), self) + || pub_use_of_private_extern_crate_hack(import, binding) { import.vis.get() } else { @@ -1188,7 +1196,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // All namespaces must be re-exported with extra visibility for an error to occur. if !any_successful_reexport { let (ns, binding) = reexport_error.unwrap(); - if ns == TypeNS && binding.is_extern_crate() { + if pub_use_of_private_extern_crate_hack(import, binding) { let msg = format!( "extern crate `{}` is private, and cannot be \ re-exported (error E0365), consider declaring with \ diff --git a/src/test/rustdoc/extern-links.rs b/src/test/rustdoc/extern-links.rs index 991f869138d93..0383ccf7db666 100644 --- a/src/test/rustdoc/extern-links.rs +++ b/src/test/rustdoc/extern-links.rs @@ -3,7 +3,7 @@ #![crate_name = "foo"] -extern crate extern_links; +pub extern crate extern_links; // @!has foo/index.html '//a' 'extern_links' #[doc(no_inline)] diff --git a/src/test/rustdoc/issue-28927.rs b/src/test/rustdoc/issue-28927.rs index 7b535f33bf7e3..38a520850b6dd 100644 --- a/src/test/rustdoc/issue-28927.rs +++ b/src/test/rustdoc/issue-28927.rs @@ -2,5 +2,5 @@ // aux-build:issue-28927-1.rs // ignore-cross-compile -extern crate issue_28927_1 as inner1; +pub extern crate issue_28927_1 as inner1; pub use inner1 as foo; diff --git a/src/test/ui/pub/pub-reexport-priv-extern-crate.rs b/src/test/ui/pub/pub-reexport-priv-extern-crate.rs index e95d6924026ca..dd5cd420fa546 100644 --- a/src/test/ui/pub/pub-reexport-priv-extern-crate.rs +++ b/src/test/ui/pub/pub-reexport-priv-extern-crate.rs @@ -1,5 +1,3 @@ -#![allow(unused)] - extern crate core; pub use core as reexported_core; //~ ERROR `core` is private, and cannot be re-exported //~^ WARN this was previously accepted @@ -9,16 +7,14 @@ mod foo1 { } mod foo2 { - use foo1::core; //~ ERROR `core` is private, and cannot be re-exported - //~^ WARN this was previously accepted + use foo1::core; //~ ERROR crate import `core` is private pub mod bar { extern crate core; } } mod baz { - pub use foo2::bar::core; //~ ERROR `core` is private, and cannot be re-exported - //~^ WARN this was previously accepted + pub use foo2::bar::core; //~ ERROR crate import `core` is private } fn main() {} diff --git a/src/test/ui/pub/pub-reexport-priv-extern-crate.stderr b/src/test/ui/pub/pub-reexport-priv-extern-crate.stderr index 0b44c5a6525f6..e4d73c6475dc4 100644 --- a/src/test/ui/pub/pub-reexport-priv-extern-crate.stderr +++ b/src/test/ui/pub/pub-reexport-priv-extern-crate.stderr @@ -1,30 +1,37 @@ -error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub` - --> $DIR/pub-reexport-priv-extern-crate.rs:4:9 +error[E0603]: crate import `core` is private + --> $DIR/pub-reexport-priv-extern-crate.rs:10:15 | -LL | pub use core as reexported_core; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | use foo1::core; + | ^^^^ private crate import | - = note: `#[deny(pub_use_of_private_extern_crate)]` 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 #34537 +note: the crate import `core` is defined here + --> $DIR/pub-reexport-priv-extern-crate.rs:6:5 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ -error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub` - --> $DIR/pub-reexport-priv-extern-crate.rs:12:9 +error[E0603]: crate import `core` is private + --> $DIR/pub-reexport-priv-extern-crate.rs:17:24 | -LL | use foo1::core; - | ^^^^^^^^^^ +LL | pub use foo2::bar::core; + | ^^^^ private crate import | - = 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 #34537 +note: the crate import `core` is defined here + --> $DIR/pub-reexport-priv-extern-crate.rs:12:9 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub` - --> $DIR/pub-reexport-priv-extern-crate.rs:20:13 + --> $DIR/pub-reexport-priv-extern-crate.rs:2:9 | -LL | pub use foo2::bar::core; - | ^^^^^^^^^^^^^^^ +LL | pub use core as reexported_core; + | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: `#[deny(pub_use_of_private_extern_crate)]` 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 #34537 error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0603`. From 49310cee30510170946561814c0a87b4dc8e667d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 11 Feb 2021 10:37:31 -0800 Subject: [PATCH 25/67] Add test for "const stability on macro" --- compiler/rustc_expand/src/base.rs | 7 +++++-- .../ui/attributes/const-stability-on-macro.rs | 13 ++++++++++++ .../const-stability-on-macro.stderr | 20 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/attributes/const-stability-on-macro.rs create mode 100644 src/test/ui/attributes/const-stability-on-macro.stderr diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index bd93e34af680b..5652d77990895 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -774,8 +774,11 @@ impl SyntaxExtension { sess.parse_sess .span_diagnostic .struct_span_err(sp, "macros cannot have const stability attributes") - .span_label(sp, "invalid stability attribute") - .span_label(span, "in this macro") + .span_label(sp, "invalid const stability attribute") + .span_label( + sess.source_map().guess_head_span(span), + "const stability attribute affects this macro", + ) .emit(); } diff --git a/src/test/ui/attributes/const-stability-on-macro.rs b/src/test/ui/attributes/const-stability-on-macro.rs new file mode 100644 index 0000000000000..3fc60f7ce48c2 --- /dev/null +++ b/src/test/ui/attributes/const-stability-on-macro.rs @@ -0,0 +1,13 @@ +#[rustc_const_stable(feature = "foo", since = "0")] +//~^ ERROR macros cannot have const stability attributes +macro_rules! foo { + () => {}; +} + +#[rustc_const_unstable(feature = "bar", issue="none")] +//~^ ERROR macros cannot have const stability attributes +macro_rules! bar { + () => {}; +} + +fn main() {} diff --git a/src/test/ui/attributes/const-stability-on-macro.stderr b/src/test/ui/attributes/const-stability-on-macro.stderr new file mode 100644 index 0000000000000..ef24e44d1908b --- /dev/null +++ b/src/test/ui/attributes/const-stability-on-macro.stderr @@ -0,0 +1,20 @@ +error: macros cannot have const stability attributes + --> $DIR/const-stability-on-macro.rs:1:1 + | +LL | #[rustc_const_stable(feature = "foo", since = "0")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute +LL | +LL | macro_rules! foo { + | ---------------- const stability attribute affects this macro + +error: macros cannot have const stability attributes + --> $DIR/const-stability-on-macro.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "bar", issue="none")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute +LL | +LL | macro_rules! bar { + | ---------------- const stability attribute affects this macro + +error: aborting due to 2 previous errors + From fbd575aedf1a60ca5528d5be945639e02d44b3e7 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 22 Feb 2021 14:30:03 +0000 Subject: [PATCH 26/67] process::unix: Handle other wait statuses in ExitStatus as Display Currently, on Nightly, this panics: ``` use std::process::ExitStatus; use std::os::unix::process::ExitStatusExt; fn main() { let st = ExitStatus::from_raw(0x007f); println!("st = {}", st); } ``` This is because the impl of Display assumes that if .code() is None, .signal() must be Some. That was a false assumption, although it was true with buggy code before 5b1316f78152a9c066b357ea9addf803d48e114a unix ExitStatus: Do not treat WIFSTOPPED as WIFSIGNALED This is not likely to have affected many people in practice, because `Command` will never produce such a wait status (`ExitStatus`). Signed-off-by: Ian Jackson --- library/std/src/sys/unix/process/process_unix.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 9e82df7755e89..26cbb0a508318 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -527,9 +527,18 @@ impl fmt::Display for ExitStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(code) = self.code() { write!(f, "exit code: {}", code) + } else if let Some(signal) = self.signal() { + if self.core_dumped() { + write!(f, "signal: {} (core dumped)", signal) + } else { + write!(f, "signal: {}", signal) + } + } else if let Some(signal) = self.stopped_signal() { + write!(f, "stopped (not terminated) by signal: {}", signal) + } else if self.continued() { + write!(f, "continued (WIFCONTINUED)") } else { - let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) + write!(f, "unrecognised wait status: {} {:#x}", self.0, self.0) } } } From d8cfd56985bd8cc32274bfead4b1499da1c38810 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 22 Feb 2021 14:58:52 +0000 Subject: [PATCH 27/67] process::unix: Test wait status formatting Signed-off-by: Ian Jackson --- .../std/src/sys/unix/process/process_unix.rs | 4 ++++ .../sys/unix/process/process_unix/tests.rs | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 library/std/src/sys/unix/process/process_unix/tests.rs diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 26cbb0a508318..d2ef0eb128c5d 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -542,3 +542,7 @@ impl fmt::Display for ExitStatus { } } } + +#[cfg(test)] +#[path = "process_unix/tests.rs"] +mod tests; diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs new file mode 100644 index 0000000000000..60cb161aca2ab --- /dev/null +++ b/library/std/src/sys/unix/process/process_unix/tests.rs @@ -0,0 +1,22 @@ +#[test] +fn exitstatus_display_tests() { + // In practice this is the same on every Unix. + // If some weird platform turns out to be different, and this test fails, use #[cfg]. + use crate::os::unix::process::ExitStatusExt; + use crate::process::ExitStatus; + + let t = |v, s| assert_eq!(s, format!("{}", ::from_raw(v))); + + t(0x0000f, "signal: 15"); + t(0x0008b, "signal: 11 (core dumped)"); + t(0x00000, "exit code: 0"); + t(0x0ff00, "exit code: 255"); + t(0x0137f, "stopped (not terminated) by signal: 19"); + t(0x0ffff, "continued (WIFCONTINUED)"); + + // Testing "unrecognised wait status" is hard because the wait.h macros typically + // assume that the value came from wait and isn't mad. With the glibc I have here + // this works: + #[cfg(target_env = "gnu")] + t(0x000ff, "unrecognised wait status: 255 0xff"); +} From 4bb8425af60eb673a932c90ee8d1b5f24c13a34e Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 22 Feb 2021 15:26:19 +0000 Subject: [PATCH 28/67] ExitStatus: Improve documentation re wait status vs exit status The use of `ExitStatus` as the Rust type name for a Unix *wait status*, not an *exit status*, is very confusing, but sadly probably too late to change. This area is confusing enough in Unix already (and many programmers are already confuxed). We can at least document it. I chose *not* to mention the way shells like to exit with signal numbers, thus turning signal numbers into exit statuses. This is only relevant for Rust programs using `std::process` if they run shells. Signed-off-by: Ian Jackson --- library/std/src/process.rs | 25 ++++++++++++++++++------- library/std/src/sys/unix/ext/process.rs | 14 ++++++++++++-- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 6480e654c55f0..15ac9e402c589 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -885,7 +885,7 @@ impl Command { } /// Executes a command as a child process, waiting for it to finish and - /// collecting its exit status. + /// collecting its status. /// /// By default, stdin, stdout and stderr are inherited from the parent. /// @@ -899,7 +899,7 @@ impl Command { /// .status() /// .expect("failed to execute process"); /// - /// println!("process exited with: {}", status); + /// println!("process finished with: {}", status); /// /// assert!(status.success()); /// ``` @@ -1368,11 +1368,17 @@ impl From for Stdio { /// Describes the result of a process after it has terminated. /// -/// This `struct` is used to represent the exit status of a child process. +/// This `struct` is used to represent the exit status or other termination of a child process. /// Child processes are created via the [`Command`] struct and their exit /// status is exposed through the [`status`] method, or the [`wait`] method /// of a [`Child`] process. /// +/// An `ExitStatus` represents every possible disposition of a process. On Unix this +/// is the **wait status**. It is *not* simply an *exit status* (a value passed to `exit`). +/// +/// For proper error reporting of failed processes, print the value of `ExitStatus` using its +/// implementation of [`Display`](crate::fmt::Display). +/// /// [`status`]: Command::status /// [`wait`]: Child::wait #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -1400,7 +1406,7 @@ impl ExitStatus { /// if status.success() { /// println!("'projects/' directory created"); /// } else { - /// println!("failed to create 'projects/' directory"); + /// println!("failed to create 'projects/' directory: {}", status); /// } /// ``` #[stable(feature = "process", since = "1.0.0")] @@ -1410,9 +1416,14 @@ impl ExitStatus { /// Returns the exit code of the process, if any. /// - /// On Unix, this will return `None` if the process was terminated - /// by a signal; `std::os::unix` provides an extension trait for - /// extracting the signal and other details from the `ExitStatus`. + /// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the + /// process finished by calling `exit`. Note that on Unix the exit status is truncated to 8 + /// bits, and that values that didn't come from a program's call to `exit` may be invented the + /// runtime system (often, for example, 255, 254, 127 or 126). + /// + /// On Unix, this will return `None` if the process was terminated by a signal. + /// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt) is an + /// extension trait for extracting any such signal, and other details, from the `ExitStatus`. /// /// # Examples /// diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 7559c1f1d9e29..6dc2033289a4a 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -186,12 +186,20 @@ impl CommandExt for process::Command { /// Unix-specific extensions to [`process::ExitStatus`]. /// +/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as passed to the +/// `exit` system call or returned by [`ExitStatus::code()`](crate::process::ExitStatus::code). +/// It represents **any wait status**, as returned by one of the `wait` family of system calls. +/// +/// This is because a Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but +/// can also represent other kinds of process event. +/// /// This trait is sealed: it cannot be implemented outside the standard library. /// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt: Sealed { - /// Creates a new `ExitStatus` from the raw underlying `i32` return value of - /// a process. + /// Creates a new `ExitStatus` from the raw underlying integer status value from `wait` + /// + /// The value should be a **wait status, not an exit status**. #[stable(feature = "exit_status_from", since = "1.12.0")] fn from_raw(raw: i32) -> Self; @@ -220,6 +228,8 @@ pub trait ExitStatusExt: Sealed { fn continued(&self) -> bool; /// Returns the underlying raw `wait` status. + /// + /// The returned integer is a **wait status, not an exit status**. #[unstable(feature = "unix_process_wait_more", issue = "80695")] fn into_raw(self) -> i32; } From 2f04a793ae0b9331f6d853a971a670c8ea99b0b7 Mon Sep 17 00:00:00 2001 From: Waffle Date: Sat, 27 Feb 2021 00:20:46 +0300 Subject: [PATCH 29/67] Revert `Vec::spare_capacity_mut` impl to prevent pointers invalidation --- library/alloc/src/vec/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b1b2619428366..e5545d2a77ff7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1879,7 +1879,15 @@ impl Vec { #[unstable(feature = "vec_spare_capacity", issue = "75017")] #[inline] pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { - self.split_at_spare_mut().1 + // Note: + // This method is not implemented in terms of `split_at_spare_mut`, + // to prevent invalidation of pointers to the buffer. + unsafe { + slice::from_raw_parts_mut( + self.as_mut_ptr().add(self.len) as *mut MaybeUninit, + self.buf.capacity() - self.len, + ) + } } /// Returns vector content as a slice of `T`, along with the remaining spare From cc62018e61edfa9706b8e4e61d1b571bdee7827d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 29 Dec 2020 23:16:16 -0500 Subject: [PATCH 30/67] Rename rustdoc lints to be a tool lint instead of built-in. - Rename `broken_intra_doc_links` to `rustdoc::broken_intra_doc_links` - Ensure that the old lint names still work and give deprecation errors - Register lints even when running doctests Otherwise, all `rustdoc::` lints would be ignored. - Register all existing lints as removed This unfortunately doesn't work with `register_renamed` because tool lints have not yet been registered when rustc is running. For similar reasons, `check_backwards_compat` doesn't work either. Call `register_removed` directly instead. - Fix fallout + Rustdoc lints for compiler/ + Rustdoc lints for library/ Note that this does *not* suggest `rustdoc::broken_intra_doc_links` for `rustdoc::intra_doc_link_resolution_failure`, since there was no time when the latter was valid. --- compiler/rustc_ast/src/attr/mod.rs | 2 +- compiler/rustc_error_codes/src/lib.rs | 3 +- compiler/rustc_lint/src/context.rs | 6 +- compiler/rustc_lint/src/lib.rs | 34 +++-- compiler/rustc_lint_defs/src/builtin.rs | 83 ---------- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/lib.rs | 3 +- src/bootstrap/builder.rs | 18 ++- src/librustdoc/core.rs | 144 ++++++++++++++---- src/librustdoc/doctest.rs | 10 +- src/librustdoc/html/markdown.rs | 3 +- src/librustdoc/lib.rs | 1 + .../passes/collect_intra_doc_links.rs | 6 +- src/librustdoc/passes/doc_test_lints.rs | 7 +- src/librustdoc/passes/html_tags.rs | 3 +- src/librustdoc/passes/non_autolinks.rs | 3 +- .../rustdoc-ui/assoc-item-not-in-scope.rs | 2 +- .../rustdoc-ui/assoc-item-not-in-scope.stderr | 4 +- src/test/rustdoc-ui/check-attr-test.rs | 2 +- src/test/rustdoc-ui/check-attr-test.stderr | 4 +- src/test/rustdoc-ui/check-attr.rs | 2 +- src/test/rustdoc-ui/check-attr.stderr | 4 +- src/test/rustdoc-ui/check-fail.stderr | 4 +- src/test/rustdoc-ui/check.stderr | 2 +- .../deny-intra-link-resolution-failure.rs | 2 +- .../deny-intra-link-resolution-failure.stderr | 4 +- src/test/rustdoc-ui/doc-without-codeblock.rs | 2 +- .../rustdoc-ui/doc-without-codeblock.stderr | 6 +- src/test/rustdoc-ui/intra-doc/alias-ice.rs | 2 +- .../rustdoc-ui/intra-doc/alias-ice.stderr | 4 +- src/test/rustdoc-ui/intra-doc/ambiguity.rs | 2 +- .../rustdoc-ui/intra-doc/ambiguity.stderr | 4 +- src/test/rustdoc-ui/intra-doc/anchors.rs | 2 +- src/test/rustdoc-ui/intra-doc/anchors.stderr | 4 +- .../rustdoc-ui/intra-doc/broken-reexport.rs | 2 +- .../intra-doc/disambiguator-mismatch.rs | 2 +- .../intra-doc/disambiguator-mismatch.stderr | 4 +- .../rustdoc-ui/intra-doc/double-anchor.stderr | 2 +- src/test/rustdoc-ui/intra-doc/errors.rs | 2 +- src/test/rustdoc-ui/intra-doc/errors.stderr | 4 +- .../incompatible-primitive-disambiguator.rs | 2 +- ...ncompatible-primitive-disambiguator.stderr | 4 +- .../intra-doc/malformed-generics.rs | 2 +- .../intra-doc/malformed-generics.stderr | 4 +- .../intra-doc/non-path-primitives.rs | 2 +- .../intra-doc/non-path-primitives.stderr | 4 +- .../rustdoc-ui/intra-doc/prim-conflict.rs | 2 +- .../rustdoc-ui/intra-doc/prim-conflict.stderr | 4 +- .../intra-doc/private.private.stderr | 2 +- .../intra-doc/private.public.stderr | 2 +- .../rustdoc-ui/intra-doc/span-ice-55723.rs | 2 +- .../intra-doc/span-ice-55723.stderr | 4 +- .../intra-doc/unused-extern-crate.rs | 2 +- .../intra-doc/unused-extern-crate.stderr | 4 +- .../rustdoc-ui/intra-doc/warning-crlf.stderr | 2 +- src/test/rustdoc-ui/intra-doc/warning.stderr | 2 +- src/test/rustdoc-ui/invalid-html-tags.rs | 2 +- src/test/rustdoc-ui/invalid-html-tags.stderr | 4 +- src/test/rustdoc-ui/issue-58473-2.rs | 2 +- .../rustdoc-ui/issue-74134.private.stderr | 2 +- src/test/rustdoc-ui/issue-74134.public.stderr | 2 +- src/test/rustdoc-ui/lint-group.stderr | 8 +- .../lint-missing-doc-code-example.rs | 4 +- .../lint-missing-doc-code-example.stderr | 4 +- src/test/rustdoc-ui/private-doc-test.rs | 2 +- src/test/rustdoc-ui/private-item-doc-test.rs | 2 +- .../rustdoc-ui/private-item-doc-test.stderr | 4 +- src/test/rustdoc-ui/pub-export-lint.rs | 2 +- src/test/rustdoc-ui/pub-export-lint.stderr | 4 +- .../reference-link-reports-error-once.rs | 2 +- .../reference-link-reports-error-once.stderr | 4 +- src/test/rustdoc-ui/reference-links.rs | 2 +- src/test/rustdoc-ui/reference-links.stderr | 4 +- src/test/rustdoc-ui/unknown-renamed-lints.rs | 13 +- .../rustdoc-ui/unknown-renamed-lints.stderr | 24 ++- src/test/rustdoc-ui/url-improvements.rs | 4 +- src/test/rustdoc-ui/url-improvements.stderr | 4 +- .../rustdoc/intra-doc/non-path-primitives.rs | 2 +- 78 files changed, 301 insertions(+), 243 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 52ac7540f6943..1e224dbf83390 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -34,7 +34,7 @@ impl MarkedAttrs { } pub fn is_known_lint_tool(m_item: Ident) -> bool { - [sym::clippy, sym::rustc].contains(&m_item.name) + [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item.name) } impl NestedMetaItem { diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index e4a702531442e..14ddb3e20793a 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -1,4 +1,5 @@ -#![deny(invalid_codeblock_attributes)] +#![cfg_attr(bootstrap, deny(invalid_codeblock_attributes))] +#![cfg_attr(not(bootstrap), deny(rustdoc::invalid_codeblock_attributes))] //! This library is used to gather all error codes into one place, //! the goal being to make their maintenance easier. diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b8db51f590d84..7d5577cdca663 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -89,6 +89,7 @@ impl SessionLintStore for LintStore { } /// The target of the `by_name` map, which accounts for renaming/deprecation. +#[derive(Debug)] enum TargetLint { /// A direct lint target Id(LintId), @@ -470,7 +471,10 @@ impl LintStore { Some(&Id(ref id)) => { CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name))) } - _ => CheckLintNameResult::NoLint(None), + Some(other) => { + tracing::debug!("got renamed lint {:?}", other); + CheckLintNameResult::NoLint(None) + } } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 638b73c27a8d7..67c0e999f5518 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -69,9 +69,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ - BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS, - EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS, - MISSING_DOC_CODE_EXAMPLES, NON_AUTOLINKS, PRIVATE_DOC_TESTS, + BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, }; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -314,17 +312,6 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { // MACRO_USE_EXTERN_CRATE ); - add_lint_group!( - "rustdoc", - NON_AUTOLINKS, - BROKEN_INTRA_DOC_LINKS, - PRIVATE_INTRA_DOC_LINKS, - INVALID_CODEBLOCK_ATTRIBUTES, - MISSING_DOC_CODE_EXAMPLES, - PRIVATE_DOC_TESTS, - INVALID_HTML_TAGS - ); - // Register renamed and removed lints. store.register_renamed("single_use_lifetime", "single_use_lifetimes"); store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths"); @@ -334,8 +321,25 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { store.register_renamed("async_idents", "keyword_idents"); store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); store.register_renamed("redundant_semicolon", "redundant_semicolons"); - store.register_renamed("intra_doc_link_resolution_failure", "broken_intra_doc_links"); store.register_renamed("overlapping_patterns", "overlapping_range_endpoints"); + + // These were moved to tool lints, but rustc still sees them when compiling normally, before + // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use + // `register_renamed` explicitly. + const RUSTDOC_LINTS: &[&str] = &[ + "broken_intra_doc_links", + "private_intra_doc_links", + "missing_doc_code_examples", + "private_doc_tests", + "invalid_codeblock_attributes", + "invalid_html_tags", + "non_autolinks", + ]; + for rustdoc_lint in RUSTDOC_LINTS { + // FIXME: maybe we could get `register_renamed` to work for tool lints? + store.register_removed(rustdoc_lint, &format!("use `rustdoc::{}` instead", rustdoc_lint)); + } + store.register_removed("unknown_features", "replaced by an error"); store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); store.register_removed("negate_unsigned", "cast a signed value instead"); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 46138df07bf69..53bb0fb28a65b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1875,39 +1875,6 @@ declare_lint! { "detects labels that are never used" } -declare_lint! { - /// The `broken_intra_doc_links` lint detects failures in resolving - /// intra-doc link targets. This is a `rustdoc` only lint, see the - /// documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links - pub BROKEN_INTRA_DOC_LINKS, - Warn, - "failures in resolving intra-doc link targets" -} - -declare_lint! { - /// This is a subset of `broken_intra_doc_links` that warns when linking from - /// a public item to a private one. This is a `rustdoc` only lint, see the - /// documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links - pub PRIVATE_INTRA_DOC_LINKS, - Warn, - "linking from a public item to a private one" -} - -declare_lint! { - /// The `invalid_codeblock_attributes` lint detects code block attributes - /// in documentation examples that have potentially mis-typed values. This - /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes - pub INVALID_CODEBLOCK_ATTRIBUTES, - Warn, - "codeblock attribute looks a lot like a known one" -} - declare_lint! { /// The `missing_crate_level_docs` lint detects if documentation is /// missing at the crate root. This is a `rustdoc` only lint, see the @@ -1919,49 +1886,6 @@ declare_lint! { "detects crates with no crate-level documentation" } -declare_lint! { - /// The `missing_doc_code_examples` lint detects publicly-exported items - /// without code samples in their documentation. This is a `rustdoc` only - /// lint, see the documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples - pub MISSING_DOC_CODE_EXAMPLES, - Allow, - "detects publicly-exported items without code samples in their documentation" -} - -declare_lint! { - /// The `private_doc_tests` lint detects code samples in docs of private - /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see - /// the documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests - pub PRIVATE_DOC_TESTS, - Allow, - "detects code samples in docs of private items not documented by rustdoc" -} - -declare_lint! { - /// The `invalid_html_tags` lint detects invalid HTML tags. This is a - /// `rustdoc` only lint, see the documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags - pub INVALID_HTML_TAGS, - Allow, - "detects invalid HTML tags in doc comments" -} - -declare_lint! { - /// The `non_autolinks` lint detects when a URL could be written using - /// only angle brackets. This is a `rustdoc` only lint, see the - /// documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#non_autolinks - pub NON_AUTOLINKS, - Warn, - "detects URLs that could be written using only angle brackets" -} - declare_lint! { /// The `where_clauses_object_safety` lint detects for [object safety] of /// [where clauses]. @@ -3020,14 +2944,7 @@ declare_lint_pass! { ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, UNSTABLE_NAME_COLLISIONS, IRREFUTABLE_LET_PATTERNS, - BROKEN_INTRA_DOC_LINKS, - PRIVATE_INTRA_DOC_LINKS, - INVALID_CODEBLOCK_ATTRIBUTES, MISSING_CRATE_LEVEL_DOCS, - MISSING_DOC_CODE_EXAMPLES, - INVALID_HTML_TAGS, - PRIVATE_DOC_TESTS, - NON_AUTOLINKS, WHERE_CLAUSES_OBJECT_SAFETY, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, MACRO_USE_EXTERN_CRATE, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f87267da9f6c7..a74ca5c1f7698 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1020,6 +1020,7 @@ symbols! { rustc_then_this_would_need, rustc_unsafe_specialization_marker, rustc_variance, + rustdoc, rustfmt, rvalue_static_promotion, sanitize, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 64e2a95130999..cb2bfa034188b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -297,7 +297,8 @@ pub mod primitive; unused_imports, unsafe_op_in_unsafe_fn )] -#[allow(non_autolinks)] +#[cfg_attr(bootstrap, allow(non_autolinks))] +#[cfg_attr(not(bootstrap), allow(rustdoc::non_autolinks))] // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. #[allow(clashing_extern_declarations)] diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 2008348ea8d8e..9317c89625d06 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -735,8 +735,15 @@ impl<'a> Builder<'a> { .env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler)) .env("CFG_RELEASE_CHANNEL", &self.config.channel) .env("RUSTDOC_REAL", self.rustdoc(compiler)) - .env("RUSTC_BOOTSTRAP", "1") - .arg("-Winvalid_codeblock_attributes"); + .env("RUSTC_BOOTSTRAP", "1"); + + // cfg(bootstrap), can be removed on the next beta bump + if compiler.stage == 0 { + cmd.arg("-Winvalid_codeblock_attributes"); + } else { + cmd.arg("-Wrustdoc::invalid_codeblock_attributes"); + } + if self.config.deny_warnings { cmd.arg("-Dwarnings"); } @@ -1292,7 +1299,12 @@ impl<'a> Builder<'a> { // fixed via better support from Cargo. cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" ")); - rustdocflags.arg("-Winvalid_codeblock_attributes"); + // cfg(bootstrap), can be removed on the next beta bump + if compiler.stage == 0 { + rustdocflags.arg("-Winvalid_codeblock_attributes"); + } else { + rustdocflags.arg("-Wrustdoc::invalid_codeblock_attributes"); + } } if mode == Mode::Rustc { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f0b3159f737a6..0dc762ea27665 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -12,6 +12,8 @@ use rustc_hir::{ Path, }; use rustc_interface::{interface, Queries}; +use rustc_lint::LintStore; +use rustc_lint_defs::{declare_tool_lint, Lint, LintId}; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; @@ -24,9 +26,11 @@ use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; +use std::cell::RefCell; +use std::collections::hash_map::Entry; +use std::lazy::SyncLazy as Lazy; use std::mem; use std::rc::Rc; -use std::{cell::RefCell, collections::hash_map::Entry}; use crate::clean; use crate::clean::inline::build_external_trait; @@ -286,6 +290,106 @@ where (lint_opts, lint_caps) } +declare_tool_lint! { + /// The `broken_intra_doc_links` lint detects failures in resolving + /// intra-doc link targets. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links + pub rustdoc::BROKEN_INTRA_DOC_LINKS, + Warn, + "failures in resolving intra-doc link targets" +} + +declare_tool_lint! { + /// This is a subset of `broken_intra_doc_links` that warns when linking from + /// a public item to a private one. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links + pub rustdoc::PRIVATE_INTRA_DOC_LINKS, + Warn, + "linking from a public item to a private one" +} + +declare_tool_lint! { + /// The `invalid_codeblock_attributes` lint detects code block attributes + /// in documentation examples that have potentially mis-typed values. This + /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes + pub rustdoc::INVALID_CODEBLOCK_ATTRIBUTES, + Warn, + "codeblock attribute looks a lot like a known one" +} + +declare_tool_lint! { + /// The `missing_doc_code_examples` lint detects publicly-exported items + /// without code samples in their documentation. This is a `rustdoc` only + /// lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples + pub rustdoc::MISSING_DOC_CODE_EXAMPLES, + Allow, + "detects publicly-exported items without code samples in their documentation" +} + +declare_tool_lint! { + /// The `private_doc_tests` lint detects code samples in docs of private + /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see + /// the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests + pub rustdoc::PRIVATE_DOC_TESTS, + Allow, + "detects code samples in docs of private items not documented by rustdoc" +} + +declare_tool_lint! { + /// The `invalid_html_tags` lint detects invalid HTML tags. This is a + /// `rustdoc` only lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags + pub rustdoc::INVALID_HTML_TAGS, + Allow, + "detects invalid HTML tags in doc comments" +} + +declare_tool_lint! { + /// The `non_autolinks` lint detects when a URL could be written using + /// only angle brackets. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#non_autolinks + pub rustdoc::NON_AUTOLINKS, + Warn, + "detects URLs that could be written using only angle brackets" +} + +static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { + vec![ + BROKEN_INTRA_DOC_LINKS, + PRIVATE_INTRA_DOC_LINKS, + MISSING_DOC_CODE_EXAMPLES, + PRIVATE_DOC_TESTS, + INVALID_CODEBLOCK_ATTRIBUTES, + INVALID_HTML_TAGS, + NON_AUTOLINKS, + ] +}); + +crate fn register_lints(_sess: &Session, lint_store: &mut LintStore) { + lint_store.register_lints(&**RUSTDOC_LINTS); + lint_store.register_group( + true, + "rustdoc", + None, + RUSTDOC_LINTS.iter().map(|&lint| LintId::of(lint)).collect(), + ); + lint_store + .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links"); +} + /// Parse, resolve, and typecheck the given crate. crate fn create_config( RustdocOptions { @@ -314,37 +418,23 @@ crate fn create_config( let cpath = Some(input.clone()); let input = Input::File(input); - let broken_intra_doc_links = lint::builtin::BROKEN_INTRA_DOC_LINKS.name; - let private_intra_doc_links = lint::builtin::PRIVATE_INTRA_DOC_LINKS.name; - let missing_docs = rustc_lint::builtin::MISSING_DOCS.name; - let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name; - let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name; - let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name; - let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name; - let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name; - let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name; - let non_autolinks = rustc_lint::builtin::NON_AUTOLINKS.name; - let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name; - // In addition to those specific lints, we also need to allow those given through // command line, otherwise they'll get ignored and we don't want that. - let lints_to_show = vec![ - broken_intra_doc_links.to_owned(), - private_intra_doc_links.to_owned(), - missing_docs.to_owned(), - missing_doc_example.to_owned(), - private_doc_tests.to_owned(), - no_crate_level_docs.to_owned(), - invalid_codeblock_attributes_name.to_owned(), - invalid_html_tags.to_owned(), - renamed_and_removed_lints.to_owned(), - unknown_lints.to_owned(), - non_autolinks.to_owned(), + let mut lints_to_show = vec![ + // it's unclear whether these should be part of rustdoc directly + rustc_lint::builtin::MISSING_DOCS.name.to_string(), + rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name.to_string(), + // these are definitely not part of rustdoc, but we want to warn on them anyway. + rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(), + rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(), ]; + lints_to_show.extend(RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string())); let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| { // FIXME: why is this necessary? - if lint.name == broken_intra_doc_links || lint.name == invalid_codeblock_attributes_name { + if lint.name == BROKEN_INTRA_DOC_LINKS.name + || lint.name == INVALID_CODEBLOCK_ATTRIBUTES.name + { None } else { Some((lint.name_lower(), lint::Allow)) @@ -384,7 +474,7 @@ crate fn create_config( diagnostic_output: DiagnosticOutput::Default, stderr: None, lint_caps, - register_lints: None, + register_lints: Some(box register_lints), override_queries: Some(|_sess, providers, _external_providers| { // Most lints will require typechecking, so just don't run them. providers.lint_mod = |_, _| {}; diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c3b9fd5a1dd42..eac0ad688d4a2 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -44,11 +44,15 @@ crate struct TestOptions { crate fn run(options: Options) -> Result<(), ErrorReported> { let input = config::Input::File(options.input.clone()); - let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name; + let invalid_codeblock_attributes_name = crate::core::INVALID_CODEBLOCK_ATTRIBUTES.name; // In addition to those specific lints, we also need to allow those given through // command line, otherwise they'll get ignored and we don't want that. - let allowed_lints = vec![invalid_codeblock_attributes_name.to_owned()]; + let allowed_lints = vec![ + invalid_codeblock_attributes_name.to_owned(), + lint::builtin::UNKNOWN_LINTS.name.to_owned(), + lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_owned(), + ]; let (lint_opts, lint_caps) = init_lints(allowed_lints, options.lint_opts.clone(), |lint| { if lint.name == invalid_codeblock_attributes_name { @@ -92,7 +96,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { diagnostic_output: DiagnosticOutput::Default, stderr: None, lint_caps, - register_lints: None, + register_lints: Some(box crate::core::register_lints), override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9a054e29dd3b5..8c8840e38e6a6 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -21,7 +21,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_middle::ty::TyCtxt; -use rustc_session::lint; use rustc_span::edition::Edition; use rustc_span::Span; use std::borrow::Cow; @@ -721,7 +720,7 @@ impl<'tcx> ExtraInfo<'tcx> { (None, None) => return, }; self.tcx.struct_span_lint_hir( - lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES, + crate::core::INVALID_CODEBLOCK_ATTRIBUTES, hir_id, self.sp, |lint| { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2342ed3ab670d..6388733c8b219 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -45,6 +45,7 @@ extern crate rustc_infer; extern crate rustc_interface; extern crate rustc_lexer; extern crate rustc_lint; +extern crate rustc_lint_defs; extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_mir; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index c047f8729adc1..6619adb5b7650 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -16,10 +16,7 @@ use rustc_hir::def_id::{CrateNum, DefId}; use rustc_middle::ty::TyCtxt; use rustc_middle::{bug, ty}; use rustc_resolve::ParentScope; -use rustc_session::lint::{ - builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}, - Lint, -}; +use rustc_session::lint::Lint; use rustc_span::hygiene::{MacroKind, SyntaxContext}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::DUMMY_SP; @@ -35,6 +32,7 @@ use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; +use crate::core::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::fold::DocFolder; use crate::html::markdown::{markdown_links, MarkdownLink}; use crate::passes::Pass; diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index e8e1bead84fb6..85547e557df5b 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -68,8 +68,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo return false; } let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local()); - let (level, source) = - cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id); + let (level, source) = cx.tcx.lint_level_at_node(crate::core::MISSING_DOC_CODE_EXAMPLES, hir_id); level != lint::Level::Allow || matches!(source, LintLevelSource::Default) } @@ -91,7 +90,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); cx.tcx.struct_span_lint_hir( - lint::builtin::MISSING_DOC_CODE_EXAMPLES, + crate::core::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, |lint| lint.build("missing code example in this documentation").emit(), @@ -99,7 +98,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { } } else if tests.found_tests > 0 && !cx.renderinfo.access_levels.is_public(item.def_id) { cx.tcx.struct_span_lint_hir( - lint::builtin::PRIVATE_DOC_TESTS, + crate::core::PRIVATE_DOC_TESTS, hir_id, span_of_attrs(&item.attrs).unwrap_or(item.source.span()), |lint| lint.build("documentation test in private item").emit(), diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index a6fe7e228d7e8..b97872c633392 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -5,7 +5,6 @@ use crate::fold::DocFolder; use crate::html::markdown::opts; use core::ops::Range; use pulldown_cmark::{Event, Parser, Tag}; -use rustc_session::lint; use std::iter::Peekable; use std::str::CharIndices; @@ -183,7 +182,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { Some(sp) => sp, None => span_of_attrs(&item.attrs).unwrap_or(item.source.span()), }; - cx.tcx.struct_span_lint_hir(lint::builtin::INVALID_HTML_TAGS, hir_id, sp, |lint| { + cx.tcx.struct_span_lint_hir(crate::core::INVALID_HTML_TAGS, hir_id, sp, |lint| { lint.build(msg).emit() }); }; diff --git a/src/librustdoc/passes/non_autolinks.rs b/src/librustdoc/passes/non_autolinks.rs index 9d4539a9769ca..fe21887fc050b 100644 --- a/src/librustdoc/passes/non_autolinks.rs +++ b/src/librustdoc/passes/non_autolinks.rs @@ -7,7 +7,6 @@ use core::ops::Range; use pulldown_cmark::{Event, LinkType, Parser, Tag}; use regex::Regex; use rustc_errors::Applicability; -use rustc_session::lint; crate const CHECK_NON_AUTOLINKS: Pass = Pass { name: "check-non-autolinks", @@ -74,7 +73,7 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> { let sp = super::source_span_for_markdown_range(cx, &dox, &range, &item.attrs) .or_else(|| span_of_attrs(&item.attrs)) .unwrap_or(item.source.span()); - cx.tcx.struct_span_lint_hir(lint::builtin::NON_AUTOLINKS, hir_id, sp, |lint| { + cx.tcx.struct_span_lint_hir(crate::core::NON_AUTOLINKS, hir_id, sp, |lint| { lint.build(msg) .span_suggestion( sp, diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.rs b/src/test/rustdoc-ui/assoc-item-not-in-scope.rs index c5bb4305db7ec..0976515f4a426 100644 --- a/src/test/rustdoc-ui/assoc-item-not-in-scope.rs +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] #[derive(Debug)] /// Link to [`S::fmt`] diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr index 92d27179e8c3f..358871b532313 100644 --- a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr @@ -7,8 +7,8 @@ LL | /// Link to [`S::fmt`] note: the lint level is defined here --> $DIR/assoc-item-not-in-scope.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/rustdoc-ui/check-attr-test.rs b/src/test/rustdoc-ui/check-attr-test.rs index 665f330e34ea5..023d620bea222 100644 --- a/src/test/rustdoc-ui/check-attr-test.rs +++ b/src/test/rustdoc-ui/check-attr-test.rs @@ -1,6 +1,6 @@ // compile-flags:--test -#![deny(invalid_codeblock_attributes)] +#![deny(rustdoc::invalid_codeblock_attributes)] /// foo /// diff --git a/src/test/rustdoc-ui/check-attr-test.stderr b/src/test/rustdoc-ui/check-attr-test.stderr index 1e067a5d21c44..affd0372a1f5e 100644 --- a/src/test/rustdoc-ui/check-attr-test.stderr +++ b/src/test/rustdoc-ui/check-attr-test.stderr @@ -11,8 +11,8 @@ error: unknown attribute `compile-fail`. Did you mean `compile_fail`? note: the lint level is defined here --> $DIR/check-attr-test.rs:3:9 | -3 | #![deny(invalid_codeblock_attributes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +3 | #![deny(rustdoc::invalid_codeblock_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully error: unknown attribute `compilefail`. Did you mean `compile_fail`? diff --git a/src/test/rustdoc-ui/check-attr.rs b/src/test/rustdoc-ui/check-attr.rs index 9e02eab753e26..763bc4c6cddb9 100644 --- a/src/test/rustdoc-ui/check-attr.rs +++ b/src/test/rustdoc-ui/check-attr.rs @@ -1,4 +1,4 @@ -#![deny(invalid_codeblock_attributes)] +#![deny(rustdoc::invalid_codeblock_attributes)] /// foo //~^ ERROR diff --git a/src/test/rustdoc-ui/check-attr.stderr b/src/test/rustdoc-ui/check-attr.stderr index 919eb047eefb5..9312cfb76f35f 100644 --- a/src/test/rustdoc-ui/check-attr.stderr +++ b/src/test/rustdoc-ui/check-attr.stderr @@ -13,8 +13,8 @@ LL | | /// ``` note: the lint level is defined here --> $DIR/check-attr.rs:1:9 | -LL | #![deny(invalid_codeblock_attributes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::invalid_codeblock_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully error: unknown attribute `compilefail`. Did you mean `compile_fail`? diff --git a/src/test/rustdoc-ui/check-fail.stderr b/src/test/rustdoc-ui/check-fail.stderr index b4f255642da53..9f5ccbc6687c2 100644 --- a/src/test/rustdoc-ui/check-fail.stderr +++ b/src/test/rustdoc-ui/check-fail.stderr @@ -21,7 +21,7 @@ note: the lint level is defined here | LL | #![deny(rustdoc)] | ^^^^^^^ - = note: `#[deny(missing_doc_code_examples)]` implied by `#[deny(rustdoc)]` + = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc)]` error: unknown attribute `testharness`. Did you mean `test_harness`? --> $DIR/check-fail.rs:6:1 @@ -37,7 +37,7 @@ note: the lint level is defined here | LL | #![deny(rustdoc)] | ^^^^^^^ - = note: `#[deny(invalid_codeblock_attributes)]` implied by `#[deny(rustdoc)]` + = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(rustdoc)]` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function error: unknown attribute `testharness`. Did you mean `test_harness`? diff --git a/src/test/rustdoc-ui/check.stderr b/src/test/rustdoc-ui/check.stderr index 27e5a736148e1..3c29a45a64a98 100644 --- a/src/test/rustdoc-ui/check.stderr +++ b/src/test/rustdoc-ui/check.stderr @@ -37,7 +37,7 @@ note: the lint level is defined here | LL | #![warn(rustdoc)] | ^^^^^^^ - = note: `#[warn(missing_doc_code_examples)]` implied by `#[warn(rustdoc)]` + = note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc)]` warning: missing code example in this documentation --> $DIR/check.rs:9:1 diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs index 54e7689f3163f..09da124b16206 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] /// [v2] //~ ERROR pub fn foo() {} diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index 9ec9dd4bc9ab7..67d9c3989f5ae 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -7,8 +7,8 @@ LL | /// [v2] note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs index 5ad8e8a826f05..6812a454157b9 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.rs +++ b/src/test/rustdoc-ui/doc-without-codeblock.rs @@ -1,4 +1,4 @@ -#![deny(missing_doc_code_examples)] //~ ERROR missing code example in this documentation +#![deny(rustdoc::missing_doc_code_examples)] //~ ERROR missing code example in this documentation /// Some docs. //~^ ERROR missing code example in this documentation diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr index 3372304f44a3d..aac537e9783cd 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.stderr +++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr @@ -1,7 +1,7 @@ error: missing code example in this documentation --> $DIR/doc-without-codeblock.rs:1:1 | -LL | / #![deny(missing_doc_code_examples)] +LL | / #![deny(rustdoc::missing_doc_code_examples)] LL | | LL | | /// Some docs. LL | | @@ -13,8 +13,8 @@ LL | | } note: the lint level is defined here --> $DIR/doc-without-codeblock.rs:1:9 | -LL | #![deny(missing_doc_code_examples)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::missing_doc_code_examples)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing code example in this documentation --> $DIR/doc-without-codeblock.rs:7:1 diff --git a/src/test/rustdoc-ui/intra-doc/alias-ice.rs b/src/test/rustdoc-ui/intra-doc/alias-ice.rs index c053e378e7147..51922caeb2543 100644 --- a/src/test/rustdoc-ui/intra-doc/alias-ice.rs +++ b/src/test/rustdoc-ui/intra-doc/alias-ice.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] pub type TypeAlias = usize; diff --git a/src/test/rustdoc-ui/intra-doc/alias-ice.stderr b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr index 3db5fad4cfbdc..5e7ffeeb8a219 100644 --- a/src/test/rustdoc-ui/intra-doc/alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr @@ -7,8 +7,8 @@ LL | /// [broken cross-reference](TypeAlias::hoge) note: the lint level is defined here --> $DIR/alias-ice.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc/ambiguity.rs b/src/test/rustdoc-ui/intra-doc/ambiguity.rs index f63435337cfbc..1f3dc722eff8d 100644 --- a/src/test/rustdoc-ui/intra-doc/ambiguity.rs +++ b/src/test/rustdoc-ui/intra-doc/ambiguity.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] diff --git a/src/test/rustdoc-ui/intra-doc/ambiguity.stderr b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr index 7e967dc88bcdd..0f23b9b8adf67 100644 --- a/src/test/rustdoc-ui/intra-doc/ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr @@ -7,8 +7,8 @@ LL | /// [true] note: the lint level is defined here --> $DIR/ambiguity.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: to link to the module, prefix with `mod@` | LL | /// [mod@true] diff --git a/src/test/rustdoc-ui/intra-doc/anchors.rs b/src/test/rustdoc-ui/intra-doc/anchors.rs index ccefd2e6fabb5..009b291be1f08 100644 --- a/src/test/rustdoc-ui/intra-doc/anchors.rs +++ b/src/test/rustdoc-ui/intra-doc/anchors.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] // A few tests on anchors. diff --git a/src/test/rustdoc-ui/intra-doc/anchors.stderr b/src/test/rustdoc-ui/intra-doc/anchors.stderr index 5b272d960d50f..97b0cea0c1e4d 100644 --- a/src/test/rustdoc-ui/intra-doc/anchors.stderr +++ b/src/test/rustdoc-ui/intra-doc/anchors.stderr @@ -7,8 +7,8 @@ LL | /// Or maybe [Foo::f#hola]. note: the lint level is defined here --> $DIR/anchors.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `hello#people#!` contains multiple anchors --> $DIR/anchors.rs:31:28 diff --git a/src/test/rustdoc-ui/intra-doc/broken-reexport.rs b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs index ef261359ebd9e..862faa50b4ddd 100644 --- a/src/test/rustdoc-ui/intra-doc/broken-reexport.rs +++ b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs @@ -1,7 +1,7 @@ // aux-build:intra-doc-broken.rs // check-pass -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] extern crate intra_doc_broken; diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs index b9c8e033b1b21..596623190a33f 100644 --- a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] //~^ NOTE lint level is defined pub enum S {} diff --git a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr index 2f5f3daa29785..5d4d4a699e4f3 100644 --- a/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -7,8 +7,8 @@ LL | /// Link to [struct@S] note: the lint level is defined here --> $DIR/disambiguator-mismatch.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this link resolved to an enum, which is not a struct error: incompatible link kind for `S` diff --git a/src/test/rustdoc-ui/intra-doc/double-anchor.stderr b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr index 1cd9231eded4d..c0241b98b78c1 100644 --- a/src/test/rustdoc-ui/intra-doc/double-anchor.stderr +++ b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr @@ -4,7 +4,7 @@ warning: `with#anchor#error` contains multiple anchors LL | /// docs [label][with#anchor#error] | ^^^^^^^^^^^^^^^^^ contains invalid anchor | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/intra-doc/errors.rs b/src/test/rustdoc-ui/intra-doc/errors.rs index 81e42643ae8fc..b29f7c29b5d86 100644 --- a/src/test/rustdoc-ui/intra-doc/errors.rs +++ b/src/test/rustdoc-ui/intra-doc/errors.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] //~^ NOTE lint level is defined // FIXME: this should say that it was skipped (maybe an allowed by default lint?) diff --git a/src/test/rustdoc-ui/intra-doc/errors.stderr b/src/test/rustdoc-ui/intra-doc/errors.stderr index 21c806108e3af..061151720578b 100644 --- a/src/test/rustdoc-ui/intra-doc/errors.stderr +++ b/src/test/rustdoc-ui/intra-doc/errors.stderr @@ -7,8 +7,8 @@ LL | /// [path::to::nonexistent::module] note: the lint level is defined here --> $DIR/errors.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved link to `path::to::nonexistent::macro` --> $DIR/errors.rs:11:6 diff --git a/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs index 0d1d5d1134b7b..3088bcd46531e 100644 --- a/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs +++ b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.rs @@ -1,3 +1,3 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] //! [static@u8::MIN] //~^ ERROR incompatible link kind diff --git a/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr index ed1c10f9e0cb8..d4dcc493c8b6a 100644 --- a/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr +++ b/src/test/rustdoc-ui/intra-doc/incompatible-primitive-disambiguator.stderr @@ -7,8 +7,8 @@ LL | //! [static@u8::MIN] note: the lint level is defined here --> $DIR/incompatible-primitive-disambiguator.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this link resolved to an associated constant, which is not a static error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc/malformed-generics.rs b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs index 9c54092146fef..15e02925ed90d 100644 --- a/src/test/rustdoc-ui/intra-doc/malformed-generics.rs +++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] //! [Vec<] //~ ERROR //! [Vec $DIR/malformed-generics.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unresolved link to `Vec $DIR/malformed-generics.rs:4:6 diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs index 6785c4c43f541..75159979e8890 100644 --- a/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs +++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] #![feature(intra_doc_pointers)] // These are links that could reasonably expected to work, but don't. diff --git a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr index 174758504ae22..610c830560527 100644 --- a/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr +++ b/src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr @@ -7,8 +7,8 @@ LL | //! [[T]::rotate_left] note: the lint level is defined here --> $DIR/non-path-primitives.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `Z` diff --git a/src/test/rustdoc-ui/intra-doc/prim-conflict.rs b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs index 85738ceae8e61..2c1a8b5357aa1 100644 --- a/src/test/rustdoc-ui/intra-doc/prim-conflict.rs +++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] //~^ NOTE lint level is defined /// [char] diff --git a/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr index 01275f8d9afb0..e4bd9fd4b8f1a 100644 --- a/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr +++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr @@ -7,8 +7,8 @@ LL | /// [char] note: the lint level is defined here --> $DIR/prim-conflict.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: to link to the module, prefix with `mod@` | LL | /// [mod@char] diff --git a/src/test/rustdoc-ui/intra-doc/private.private.stderr b/src/test/rustdoc-ui/intra-doc/private.private.stderr index 94a833fcc1a15..cae5b1f20e6c3 100644 --- a/src/test/rustdoc-ui/intra-doc/private.private.stderr +++ b/src/test/rustdoc-ui/intra-doc/private.private.stderr @@ -4,7 +4,7 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` LL | /// docs [DontDocMe] [DontDocMe::f] | ^^^^^^^^^ this item is private | - = note: `#[warn(private_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without warning: public documentation for `DocMe` links to private item `DontDocMe::f` diff --git a/src/test/rustdoc-ui/intra-doc/private.public.stderr b/src/test/rustdoc-ui/intra-doc/private.public.stderr index 21a60638d5efc..05b202e37fbcb 100644 --- a/src/test/rustdoc-ui/intra-doc/private.public.stderr +++ b/src/test/rustdoc-ui/intra-doc/private.public.stderr @@ -4,7 +4,7 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` LL | /// docs [DontDocMe] [DontDocMe::f] | ^^^^^^^^^ this item is private | - = note: `#[warn(private_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` warning: public documentation for `DocMe` links to private item `DontDocMe::f` diff --git a/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs index 7764a6df6ee77..041ec29325923 100644 --- a/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs +++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] // An error in calculating spans while reporting intra-doc link resolution errors caused rustdoc to // attempt to slice in the middle of a multibyte character. See diff --git a/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr index 10ca14e850fd7..bf4ab9fdd18b1 100644 --- a/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr @@ -7,8 +7,8 @@ LL | /// (arr[i]) note: the lint level is defined here --> $DIR/span-ice-55723.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs index 186503cf69d3f..9565830930f41 100644 --- a/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs +++ b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.rs @@ -1,5 +1,5 @@ // compile-flags: --extern zip=whatever.rlib -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] /// See [zip] crate. //~^ ERROR unresolved pub struct ArrayZip; diff --git a/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr index b3b57fd131838..5c0df1d1b9e4f 100644 --- a/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr +++ b/src/test/rustdoc-ui/intra-doc/unused-extern-crate.stderr @@ -7,8 +7,8 @@ LL | /// See [zip] crate. note: the lint level is defined here --> $DIR/unused-extern-crate.rs:2:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr index 01e4282003766..d46df92649d17 100644 --- a/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr @@ -4,7 +4,7 @@ warning: unresolved link to `error` LL | /// [error] | ^^^^^ no item named `error` in scope | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` diff --git a/src/test/rustdoc-ui/intra-doc/warning.stderr b/src/test/rustdoc-ui/intra-doc/warning.stderr index 430d18165a005..135c432e05342 100644 --- a/src/test/rustdoc-ui/intra-doc/warning.stderr +++ b/src/test/rustdoc-ui/intra-doc/warning.stderr @@ -4,7 +4,7 @@ warning: unresolved link to `Foo::baz` LL | //! Test with [Foo::baz], [Bar::foo], ... | ^^^^^^^^ the struct `Foo` has no field or associated item named `baz` | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: unresolved link to `Bar::foo` --> $DIR/warning.rs:3:35 diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs index 9c2fc4beb5eb1..cec44b6d2ca62 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.rs +++ b/src/test/rustdoc-ui/invalid-html-tags.rs @@ -1,4 +1,4 @@ -#![deny(invalid_html_tags)] +#![deny(rustdoc::invalid_html_tags)] //!

💩

//~^ ERROR unclosed HTML tag `p` diff --git a/src/test/rustdoc-ui/invalid-html-tags.stderr b/src/test/rustdoc-ui/invalid-html-tags.stderr index aa9ace006bd1a..335e100c89d89 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.stderr +++ b/src/test/rustdoc-ui/invalid-html-tags.stderr @@ -7,8 +7,8 @@ LL | //!

💩

note: the lint level is defined here --> $DIR/invalid-html-tags.rs:1:9 | -LL | #![deny(invalid_html_tags)] - | ^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unclosed HTML tag `p` --> $DIR/invalid-html-tags.rs:3:9 diff --git a/src/test/rustdoc-ui/issue-58473-2.rs b/src/test/rustdoc-ui/issue-58473-2.rs index e5f3b4daf5729..000b6a329c1a7 100644 --- a/src/test/rustdoc-ui/issue-58473-2.rs +++ b/src/test/rustdoc-ui/issue-58473-2.rs @@ -1,6 +1,6 @@ // check-pass -#![deny(private_doc_tests)] +#![deny(rustdoc::private_doc_tests)] mod foo { /** diff --git a/src/test/rustdoc-ui/issue-74134.private.stderr b/src/test/rustdoc-ui/issue-74134.private.stderr index b802d7e12523a..457987e207496 100644 --- a/src/test/rustdoc-ui/issue-74134.private.stderr +++ b/src/test/rustdoc-ui/issue-74134.private.stderr @@ -4,7 +4,7 @@ warning: public documentation for `public_item` links to private item `PrivateTy LL | /// [`PrivateType`] | ^^^^^^^^^^^^^ this item is private | - = note: `#[warn(private_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr index 40aa2ece1a373..07aebc3541fe3 100644 --- a/src/test/rustdoc-ui/issue-74134.public.stderr +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -4,7 +4,7 @@ warning: public documentation for `public_item` links to private item `PrivateTy LL | /// [`PrivateType`] | ^^^^^^^^^^^^^ this item is private | - = note: `#[warn(private_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 0c111a33b6564..6f8a20f7d53f0 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(rustdoc)] | ^^^^^^^ - = note: `#[deny(missing_doc_code_examples)]` implied by `#[deny(rustdoc)]` + = note: `#[deny(rustdoc::missing_doc_code_examples)]` implied by `#[deny(rustdoc)]` error: documentation test in private item --> $DIR/lint-group.rs:19:1 @@ -26,7 +26,7 @@ note: the lint level is defined here | LL | #![deny(rustdoc)] | ^^^^^^^ - = note: `#[deny(private_doc_tests)]` implied by `#[deny(rustdoc)]` + = note: `#[deny(rustdoc::private_doc_tests)]` implied by `#[deny(rustdoc)]` error: missing code example in this documentation --> $DIR/lint-group.rs:26:1 @@ -45,7 +45,7 @@ note: the lint level is defined here | LL | #![deny(rustdoc)] | ^^^^^^^ - = note: `#[deny(broken_intra_doc_links)]` implied by `#[deny(rustdoc)]` + = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(rustdoc)]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unclosed HTML tag `unknown` @@ -59,7 +59,7 @@ note: the lint level is defined here | LL | #![deny(rustdoc)] | ^^^^^^^ - = note: `#[deny(invalid_html_tags)]` implied by `#[deny(rustdoc)]` + = note: `#[deny(rustdoc::invalid_html_tags)]` implied by `#[deny(rustdoc)]` error: aborting due to 5 previous errors diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs index ebe7a242211bf..8d727b0d0b550 100644 --- a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs @@ -1,5 +1,5 @@ #![deny(missing_docs)] -#![deny(missing_doc_code_examples)] +#![deny(rustdoc::missing_doc_code_examples)] //! crate level doc //! ``` @@ -19,7 +19,7 @@ fn test() { mod module1 { //~ ERROR } -#[allow(missing_doc_code_examples)] +#[allow(rustdoc::missing_doc_code_examples)] /// doc mod module2 { diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr index e02ed4a056c12..370c577f85d8f 100644 --- a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr @@ -8,8 +8,8 @@ LL | | } note: the lint level is defined here --> $DIR/lint-missing-doc-code-example.rs:2:9 | -LL | #![deny(missing_doc_code_examples)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::missing_doc_code_examples)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing code example in this documentation --> $DIR/lint-missing-doc-code-example.rs:37:3 diff --git a/src/test/rustdoc-ui/private-doc-test.rs b/src/test/rustdoc-ui/private-doc-test.rs index 379fa45f9fa3e..a1f9f8dca083e 100644 --- a/src/test/rustdoc-ui/private-doc-test.rs +++ b/src/test/rustdoc-ui/private-doc-test.rs @@ -1,6 +1,6 @@ // check-pass -#![deny(private_doc_tests)] +#![deny(rustdoc::private_doc_tests)] mod foo { /// private doc test diff --git a/src/test/rustdoc-ui/private-item-doc-test.rs b/src/test/rustdoc-ui/private-item-doc-test.rs index 2f1bddc7c75cc..1a3d6cc636d31 100644 --- a/src/test/rustdoc-ui/private-item-doc-test.rs +++ b/src/test/rustdoc-ui/private-item-doc-test.rs @@ -1,4 +1,4 @@ -#![deny(private_doc_tests)] +#![deny(rustdoc::private_doc_tests)] mod foo { /// private doc test diff --git a/src/test/rustdoc-ui/private-item-doc-test.stderr b/src/test/rustdoc-ui/private-item-doc-test.stderr index 70b6638b23711..5df6132987c9f 100644 --- a/src/test/rustdoc-ui/private-item-doc-test.stderr +++ b/src/test/rustdoc-ui/private-item-doc-test.stderr @@ -11,8 +11,8 @@ LL | | /// ``` note: the lint level is defined here --> $DIR/private-item-doc-test.rs:1:9 | -LL | #![deny(private_doc_tests)] - | ^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::private_doc_tests)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/rustdoc-ui/pub-export-lint.rs b/src/test/rustdoc-ui/pub-export-lint.rs index 3fd3f77400978..f2e66b77bf3ea 100644 --- a/src/test/rustdoc-ui/pub-export-lint.rs +++ b/src/test/rustdoc-ui/pub-export-lint.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] /// [aloha] //~^ ERROR unresolved link to `aloha` diff --git a/src/test/rustdoc-ui/pub-export-lint.stderr b/src/test/rustdoc-ui/pub-export-lint.stderr index c345def794c08..c6be9c6a9f504 100644 --- a/src/test/rustdoc-ui/pub-export-lint.stderr +++ b/src/test/rustdoc-ui/pub-export-lint.stderr @@ -7,8 +7,8 @@ LL | /// [aloha] note: the lint level is defined here --> $DIR/pub-export-lint.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/reference-link-reports-error-once.rs b/src/test/rustdoc-ui/reference-link-reports-error-once.rs index 7957ee373c49e..71bd2c522ff86 100644 --- a/src/test/rustdoc-ui/reference-link-reports-error-once.rs +++ b/src/test/rustdoc-ui/reference-link-reports-error-once.rs @@ -1,4 +1,4 @@ -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] /// Links to [a] [link][a] /// And also a [third link][a] diff --git a/src/test/rustdoc-ui/reference-link-reports-error-once.stderr b/src/test/rustdoc-ui/reference-link-reports-error-once.stderr index 218eb334a6fc3..b46a51e93fb8b 100644 --- a/src/test/rustdoc-ui/reference-link-reports-error-once.stderr +++ b/src/test/rustdoc-ui/reference-link-reports-error-once.stderr @@ -7,8 +7,8 @@ LL | /// [a]: ref note: the lint level is defined here --> $DIR/reference-link-reports-error-once.rs:1:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: unresolved link to `ref2` diff --git a/src/test/rustdoc-ui/reference-links.rs b/src/test/rustdoc-ui/reference-links.rs index 6e00b9f0fa1a9..e81e034465d7f 100644 --- a/src/test/rustdoc-ui/reference-links.rs +++ b/src/test/rustdoc-ui/reference-links.rs @@ -1,5 +1,5 @@ // Test that errors point to the reference, not to the title text. -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] //! Links to [a] [link][a] //! //! [a]: std::process::Comman diff --git a/src/test/rustdoc-ui/reference-links.stderr b/src/test/rustdoc-ui/reference-links.stderr index 3df89df21b4c6..c98a2fd7ce690 100644 --- a/src/test/rustdoc-ui/reference-links.stderr +++ b/src/test/rustdoc-ui/reference-links.stderr @@ -7,8 +7,8 @@ LL | //! [a]: std::process::Comman note: the lint level is defined here --> $DIR/reference-links.rs:2:9 | -LL | #![deny(broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.rs b/src/test/rustdoc-ui/unknown-renamed-lints.rs index 7faa82ea429c2..e2238a4004c1b 100644 --- a/src/test/rustdoc-ui/unknown-renamed-lints.rs +++ b/src/test/rustdoc-ui/unknown-renamed-lints.rs @@ -4,5 +4,16 @@ //~^ NOTE lint level is defined #![deny(x)] //~^ ERROR unknown lint +#![deny(rustdoc::x)] +//~^ ERROR unknown lint: `rustdoc::x` #![deny(intra_doc_link_resolution_failure)] -//~^ ERROR lint `intra_doc_link_resolution_failure` has been renamed +//~^ ERROR has been renamed + +// This would ideally say 'renamed to rustdoc::non_autolinks', but this is close enough. +#![deny(non_autolinks)] +//~^ ERROR has been removed: use `rustdoc::non_autolinks` instead [renamed_and_removed_lints] + +// This doesn't give you the right code directly, but at least points you on the +// right path. +#![deny(rustdoc::intra_doc_link_resolution_failure)] +//~^ ERROR unknown lint diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.stderr b/src/test/rustdoc-ui/unknown-renamed-lints.stderr index f0917f194bb08..1a45f68ae810f 100644 --- a/src/test/rustdoc-ui/unknown-renamed-lints.stderr +++ b/src/test/rustdoc-ui/unknown-renamed-lints.stderr @@ -10,11 +10,17 @@ note: the lint level is defined here LL | #![deny(unknown_lints)] | ^^^^^^^^^^^^^ -error: lint `intra_doc_link_resolution_failure` has been renamed to `broken_intra_doc_links` +error: unknown lint: `rustdoc::x` --> $DIR/unknown-renamed-lints.rs:7:9 | +LL | #![deny(rustdoc::x)] + | ^^^^^^^^^^ + +error: lint `intra_doc_link_resolution_failure` has been renamed to `rustdoc::broken_intra_doc_links` + --> $DIR/unknown-renamed-lints.rs:9:9 + | LL | #![deny(intra_doc_link_resolution_failure)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `broken_intra_doc_links` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links` | note: the lint level is defined here --> $DIR/unknown-renamed-lints.rs:3:9 @@ -22,7 +28,19 @@ note: the lint level is defined here LL | #![deny(renamed_and_removed_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: lint `non_autolinks` has been removed: use `rustdoc::non_autolinks` instead + --> $DIR/unknown-renamed-lints.rs:13:9 + | +LL | #![deny(non_autolinks)] + | ^^^^^^^^^^^^^ + +error: unknown lint: `rustdoc::intra_doc_link_resolution_failure` + --> $DIR/unknown-renamed-lints.rs:18:9 + | +LL | #![deny(rustdoc::intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: Compilation failed, aborting rustdoc -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/rustdoc-ui/url-improvements.rs b/src/test/rustdoc-ui/url-improvements.rs index 8531583d38a65..d0b43de2f0e0e 100644 --- a/src/test/rustdoc-ui/url-improvements.rs +++ b/src/test/rustdoc-ui/url-improvements.rs @@ -1,4 +1,4 @@ -#![deny(non_autolinks)] +#![deny(rustdoc::non_autolinks)] /// [http://aa.com](http://aa.com) //~^ ERROR unneeded long form for URL @@ -59,7 +59,7 @@ pub fn c() {} /// [should_not.lint](should_not.lint) pub fn everything_is_fine_here() {} -#[allow(non_autolinks)] +#[allow(rustdoc::non_autolinks)] pub mod foo { /// https://somewhere.com/a?hello=12&bye=11#xyz pub fn bar() {} diff --git a/src/test/rustdoc-ui/url-improvements.stderr b/src/test/rustdoc-ui/url-improvements.stderr index 70ad4b06a515d..f377973656a83 100644 --- a/src/test/rustdoc-ui/url-improvements.stderr +++ b/src/test/rustdoc-ui/url-improvements.stderr @@ -7,8 +7,8 @@ LL | /// [http://aa.com](http://aa.com) note: the lint level is defined here --> $DIR/url-improvements.rs:1:9 | -LL | #![deny(non_autolinks)] - | ^^^^^^^^^^^^^ +LL | #![deny(rustdoc::non_autolinks)] + | ^^^^^^^^^^^^^^^^^^^^^^ error: unneeded long form for URL --> $DIR/url-improvements.rs:5:5 diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs index 48c667ef2d18e..ffa02b0c635b3 100644 --- a/src/test/rustdoc/intra-doc/non-path-primitives.rs +++ b/src/test/rustdoc/intra-doc/non-path-primitives.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength #![crate_name = "foo"] #![feature(intra_doc_pointers)] -#![deny(broken_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] // @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left' //! [slice::rotate_left] From 37e4cfe5125e1d8d29fd1a66c7f80109c25618fb Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 30 Dec 2020 14:11:15 -0500 Subject: [PATCH 31/67] Move lint machinery into a separate file --- src/librustdoc/core.rs | 175 +----------------- src/librustdoc/doctest.rs | 9 +- src/librustdoc/html/markdown.rs | 2 +- src/librustdoc/lib.rs | 1 + src/librustdoc/lint.rs | 164 ++++++++++++++++ .../passes/collect_intra_doc_links.rs | 2 +- src/librustdoc/passes/doc_test_lints.rs | 6 +- src/librustdoc/passes/html_tags.rs | 2 +- src/librustdoc/passes/non_autolinks.rs | 2 +- 9 files changed, 183 insertions(+), 180 deletions(-) create mode 100644 src/librustdoc/lint.rs diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 0dc762ea27665..5313f8553a894 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -12,8 +12,6 @@ use rustc_hir::{ Path, }; use rustc_interface::{interface, Queries}; -use rustc_lint::LintStore; -use rustc_lint_defs::{declare_tool_lint, Lint, LintId}; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; @@ -28,7 +26,6 @@ use rustc_span::DUMMY_SP; use std::cell::RefCell; use std::collections::hash_map::Entry; -use std::lazy::SyncLazy as Lazy; use std::mem; use std::rc::Rc; @@ -232,164 +229,6 @@ crate fn new_handler( ) } -/// This function is used to setup the lint initialization. By default, in rustdoc, everything -/// is "allowed". Depending if we run in test mode or not, we want some of them to be at their -/// default level. For example, the "INVALID_CODEBLOCK_ATTRIBUTES" lint is activated in both -/// modes. -/// -/// A little detail easy to forget is that there is a way to set the lint level for all lints -/// through the "WARNINGS" lint. To prevent this to happen, we set it back to its "normal" level -/// inside this function. -/// -/// It returns a tuple containing: -/// * Vector of tuples of lints' name and their associated "max" level -/// * HashMap of lint id with their associated "max" level -pub(crate) fn init_lints( - mut allowed_lints: Vec, - lint_opts: Vec<(String, lint::Level)>, - filter_call: F, -) -> (Vec<(String, lint::Level)>, FxHashMap) -where - F: Fn(&lint::Lint) -> Option<(String, lint::Level)>, -{ - let warnings_lint_name = lint::builtin::WARNINGS.name; - - allowed_lints.push(warnings_lint_name.to_owned()); - allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); - - let lints = || { - lint::builtin::HardwiredLints::get_lints() - .into_iter() - .chain(rustc_lint::SoftLints::get_lints().into_iter()) - }; - - let lint_opts = lints() - .filter_map(|lint| { - // Permit feature-gated lints to avoid feature errors when trying to - // allow all lints. - if lint.feature_gate.is_some() || allowed_lints.iter().any(|l| lint.name == l) { - None - } else { - filter_call(lint) - } - }) - .chain(lint_opts.into_iter()) - .collect::>(); - - let lint_caps = lints() - .filter_map(|lint| { - // We don't want to allow *all* lints so let's ignore - // those ones. - if allowed_lints.iter().any(|l| lint.name == l) { - None - } else { - Some((lint::LintId::of(lint), lint::Allow)) - } - }) - .collect(); - (lint_opts, lint_caps) -} - -declare_tool_lint! { - /// The `broken_intra_doc_links` lint detects failures in resolving - /// intra-doc link targets. This is a `rustdoc` only lint, see the - /// documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links - pub rustdoc::BROKEN_INTRA_DOC_LINKS, - Warn, - "failures in resolving intra-doc link targets" -} - -declare_tool_lint! { - /// This is a subset of `broken_intra_doc_links` that warns when linking from - /// a public item to a private one. This is a `rustdoc` only lint, see the - /// documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links - pub rustdoc::PRIVATE_INTRA_DOC_LINKS, - Warn, - "linking from a public item to a private one" -} - -declare_tool_lint! { - /// The `invalid_codeblock_attributes` lint detects code block attributes - /// in documentation examples that have potentially mis-typed values. This - /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes - pub rustdoc::INVALID_CODEBLOCK_ATTRIBUTES, - Warn, - "codeblock attribute looks a lot like a known one" -} - -declare_tool_lint! { - /// The `missing_doc_code_examples` lint detects publicly-exported items - /// without code samples in their documentation. This is a `rustdoc` only - /// lint, see the documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples - pub rustdoc::MISSING_DOC_CODE_EXAMPLES, - Allow, - "detects publicly-exported items without code samples in their documentation" -} - -declare_tool_lint! { - /// The `private_doc_tests` lint detects code samples in docs of private - /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see - /// the documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests - pub rustdoc::PRIVATE_DOC_TESTS, - Allow, - "detects code samples in docs of private items not documented by rustdoc" -} - -declare_tool_lint! { - /// The `invalid_html_tags` lint detects invalid HTML tags. This is a - /// `rustdoc` only lint, see the documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags - pub rustdoc::INVALID_HTML_TAGS, - Allow, - "detects invalid HTML tags in doc comments" -} - -declare_tool_lint! { - /// The `non_autolinks` lint detects when a URL could be written using - /// only angle brackets. This is a `rustdoc` only lint, see the - /// documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#non_autolinks - pub rustdoc::NON_AUTOLINKS, - Warn, - "detects URLs that could be written using only angle brackets" -} - -static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { - vec![ - BROKEN_INTRA_DOC_LINKS, - PRIVATE_INTRA_DOC_LINKS, - MISSING_DOC_CODE_EXAMPLES, - PRIVATE_DOC_TESTS, - INVALID_CODEBLOCK_ATTRIBUTES, - INVALID_HTML_TAGS, - NON_AUTOLINKS, - ] -}); - -crate fn register_lints(_sess: &Session, lint_store: &mut LintStore) { - lint_store.register_lints(&**RUSTDOC_LINTS); - lint_store.register_group( - true, - "rustdoc", - None, - RUSTDOC_LINTS.iter().map(|&lint| LintId::of(lint)).collect(), - ); - lint_store - .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links"); -} - /// Parse, resolve, and typecheck the given crate. crate fn create_config( RustdocOptions { @@ -418,8 +257,8 @@ crate fn create_config( let cpath = Some(input.clone()); let input = Input::File(input); - // In addition to those specific lints, we also need to allow those given through - // command line, otherwise they'll get ignored and we don't want that. + // By default, rustdoc ignores all lints. + // Specifically unblock lints relevant to documentation or the lint machinery itself. let mut lints_to_show = vec![ // it's unclear whether these should be part of rustdoc directly rustc_lint::builtin::MISSING_DOCS.name.to_string(), @@ -428,12 +267,12 @@ crate fn create_config( rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(), rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(), ]; - lints_to_show.extend(RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string())); + lints_to_show.extend(crate::lint::RUSTDOC_LINTS.iter().map(|lint| lint.name.to_string())); - let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| { + let (lint_opts, lint_caps) = crate::lint::init_lints(lints_to_show, lint_opts, |lint| { // FIXME: why is this necessary? - if lint.name == BROKEN_INTRA_DOC_LINKS.name - || lint.name == INVALID_CODEBLOCK_ATTRIBUTES.name + if lint.name == crate::lint::BROKEN_INTRA_DOC_LINKS.name + || lint.name == crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name { None } else { @@ -474,7 +313,7 @@ crate fn create_config( diagnostic_output: DiagnosticOutput::Default, stderr: None, lint_caps, - register_lints: Some(box register_lints), + register_lints: Some(box crate::lint::register_lints), override_queries: Some(|_sess, providers, _external_providers| { // Most lints will require typechecking, so just don't run them. providers.lint_mod = |_, _| {}; diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index eac0ad688d4a2..27ce064669d2c 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -26,8 +26,8 @@ use std::str; use crate::clean::Attributes; use crate::config::Options; -use crate::core::init_lints; use crate::html::markdown::{self, ErrorCodes, Ignore, LangString}; +use crate::lint::init_lints; use crate::passes::span_of_attrs; #[derive(Clone, Default)] @@ -44,10 +44,9 @@ crate struct TestOptions { crate fn run(options: Options) -> Result<(), ErrorReported> { let input = config::Input::File(options.input.clone()); - let invalid_codeblock_attributes_name = crate::core::INVALID_CODEBLOCK_ATTRIBUTES.name; + let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name; - // In addition to those specific lints, we also need to allow those given through - // command line, otherwise they'll get ignored and we don't want that. + // See core::create_config for what's going on here. let allowed_lints = vec![ invalid_codeblock_attributes_name.to_owned(), lint::builtin::UNKNOWN_LINTS.name.to_owned(), @@ -96,7 +95,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { diagnostic_output: DiagnosticOutput::Default, stderr: None, lint_caps, - register_lints: Some(box crate::core::register_lints), + register_lints: Some(box crate::lint::register_lints), override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 8c8840e38e6a6..f8ca259fb9ab5 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -720,7 +720,7 @@ impl<'tcx> ExtraInfo<'tcx> { (None, None) => return, }; self.tcx.struct_span_lint_hir( - crate::core::INVALID_CODEBLOCK_ATTRIBUTES, + crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, hir_id, self.sp, |lint| { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 6388733c8b219..c152f0fb7f6a0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -86,6 +86,7 @@ mod formats; // used by the error-index generator, so it needs to be public pub mod html; mod json; +crate mod lint; mod markdown; mod passes; mod theme; diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs new file mode 100644 index 0000000000000..778983868ea01 --- /dev/null +++ b/src/librustdoc/lint.rs @@ -0,0 +1,164 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_lint::LintStore; +use rustc_lint_defs::{declare_tool_lint, Lint, LintId}; +use rustc_session::{lint, Session}; + +use std::lazy::SyncLazy as Lazy; + +/// This function is used to setup the lint initialization. By default, in rustdoc, everything +/// is "allowed". Depending if we run in test mode or not, we want some of them to be at their +/// default level. For example, the "INVALID_CODEBLOCK_ATTRIBUTES" lint is activated in both +/// modes. +/// +/// A little detail easy to forget is that there is a way to set the lint level for all lints +/// through the "WARNINGS" lint. To prevent this to happen, we set it back to its "normal" level +/// inside this function. +/// +/// It returns a tuple containing: +/// * Vector of tuples of lints' name and their associated "max" level +/// * HashMap of lint id with their associated "max" level +pub(crate) fn init_lints( + mut allowed_lints: Vec, + lint_opts: Vec<(String, lint::Level)>, + filter_call: F, +) -> (Vec<(String, lint::Level)>, FxHashMap) +where + F: Fn(&lint::Lint) -> Option<(String, lint::Level)>, +{ + let warnings_lint_name = lint::builtin::WARNINGS.name; + + allowed_lints.push(warnings_lint_name.to_owned()); + allowed_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); + + let lints = || { + lint::builtin::HardwiredLints::get_lints() + .into_iter() + .chain(rustc_lint::SoftLints::get_lints().into_iter()) + }; + + let lint_opts = lints() + .filter_map(|lint| { + // Permit feature-gated lints to avoid feature errors when trying to + // allow all lints. + if lint.feature_gate.is_some() || allowed_lints.iter().any(|l| lint.name == l) { + None + } else { + filter_call(lint) + } + }) + .chain(lint_opts.into_iter()) + .collect::>(); + + let lint_caps = lints() + .filter_map(|lint| { + // We don't want to allow *all* lints so let's ignore + // those ones. + if allowed_lints.iter().any(|l| lint.name == l) { + None + } else { + Some((lint::LintId::of(lint), lint::Allow)) + } + }) + .collect(); + (lint_opts, lint_caps) +} + +declare_tool_lint! { + /// The `broken_intra_doc_links` lint detects failures in resolving + /// intra-doc link targets. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links + pub rustdoc::BROKEN_INTRA_DOC_LINKS, + Warn, + "failures in resolving intra-doc link targets" +} + +declare_tool_lint! { + /// This is a subset of `broken_intra_doc_links` that warns when linking from + /// a public item to a private one. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links + pub rustdoc::PRIVATE_INTRA_DOC_LINKS, + Warn, + "linking from a public item to a private one" +} + +declare_tool_lint! { + /// The `invalid_codeblock_attributes` lint detects code block attributes + /// in documentation examples that have potentially mis-typed values. This + /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes + pub rustdoc::INVALID_CODEBLOCK_ATTRIBUTES, + Warn, + "codeblock attribute looks a lot like a known one" +} + +declare_tool_lint! { + /// The `missing_doc_code_examples` lint detects publicly-exported items + /// without code samples in their documentation. This is a `rustdoc` only + /// lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples + pub rustdoc::MISSING_DOC_CODE_EXAMPLES, + Allow, + "detects publicly-exported items without code samples in their documentation" +} + +declare_tool_lint! { + /// The `private_doc_tests` lint detects code samples in docs of private + /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see + /// the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests + pub rustdoc::PRIVATE_DOC_TESTS, + Allow, + "detects code samples in docs of private items not documented by rustdoc" +} + +declare_tool_lint! { + /// The `invalid_html_tags` lint detects invalid HTML tags. This is a + /// `rustdoc` only lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags + pub rustdoc::INVALID_HTML_TAGS, + Allow, + "detects invalid HTML tags in doc comments" +} + +declare_tool_lint! { + /// The `non_autolinks` lint detects when a URL could be written using + /// only angle brackets. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#non_autolinks + pub rustdoc::NON_AUTOLINKS, + Warn, + "detects URLs that could be written using only angle brackets" +} + +crate static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { + vec![ + BROKEN_INTRA_DOC_LINKS, + PRIVATE_INTRA_DOC_LINKS, + MISSING_DOC_CODE_EXAMPLES, + PRIVATE_DOC_TESTS, + INVALID_CODEBLOCK_ATTRIBUTES, + INVALID_HTML_TAGS, + NON_AUTOLINKS, + ] +}); + +crate fn register_lints(_sess: &Session, lint_store: &mut LintStore) { + lint_store.register_lints(&**RUSTDOC_LINTS); + lint_store.register_group( + true, + "rustdoc", + None, + RUSTDOC_LINTS.iter().map(|&lint| LintId::of(lint)).collect(), + ); + lint_store + .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links"); +} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 6619adb5b7650..38efecb393b79 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -32,9 +32,9 @@ use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; -use crate::core::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::fold::DocFolder; use crate::html::markdown::{markdown_links, MarkdownLink}; +use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::passes::Pass; use super::span_of_attrs; diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 85547e557df5b..c6b956c600058 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -68,7 +68,7 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo return false; } let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local()); - let (level, source) = cx.tcx.lint_level_at_node(crate::core::MISSING_DOC_CODE_EXAMPLES, hir_id); + let (level, source) = cx.tcx.lint_level_at_node(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id); level != lint::Level::Allow || matches!(source, LintLevelSource::Default) } @@ -90,7 +90,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); cx.tcx.struct_span_lint_hir( - crate::core::MISSING_DOC_CODE_EXAMPLES, + crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, |lint| lint.build("missing code example in this documentation").emit(), @@ -98,7 +98,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { } } else if tests.found_tests > 0 && !cx.renderinfo.access_levels.is_public(item.def_id) { cx.tcx.struct_span_lint_hir( - crate::core::PRIVATE_DOC_TESTS, + crate::lint::PRIVATE_DOC_TESTS, hir_id, span_of_attrs(&item.attrs).unwrap_or(item.source.span()), |lint| lint.build("documentation test in private item").emit(), diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index b97872c633392..27e669aa44fc0 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { Some(sp) => sp, None => span_of_attrs(&item.attrs).unwrap_or(item.source.span()), }; - cx.tcx.struct_span_lint_hir(crate::core::INVALID_HTML_TAGS, hir_id, sp, |lint| { + cx.tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, |lint| { lint.build(msg).emit() }); }; diff --git a/src/librustdoc/passes/non_autolinks.rs b/src/librustdoc/passes/non_autolinks.rs index fe21887fc050b..09a1959fa113c 100644 --- a/src/librustdoc/passes/non_autolinks.rs +++ b/src/librustdoc/passes/non_autolinks.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> { let sp = super::source_span_for_markdown_range(cx, &dox, &range, &item.attrs) .or_else(|| span_of_attrs(&item.attrs)) .unwrap_or(item.source.span()); - cx.tcx.struct_span_lint_hir(crate::core::NON_AUTOLINKS, hir_id, sp, |lint| { + cx.tcx.struct_span_lint_hir(crate::lint::NON_AUTOLINKS, hir_id, sp, |lint| { lint.build(msg) .span_suggestion( sp, From 719535576738ee97a866ce7fbf76a42d6399627b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 30 Dec 2020 14:17:18 -0500 Subject: [PATCH 32/67] Add `declare_rustdoc_lint!` macro --- src/librustdoc/lint.rs | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 778983868ea01..013b7ead5c7c9 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -63,78 +63,86 @@ where (lint_opts, lint_caps) } -declare_tool_lint! { +macro_rules! declare_rustdoc_lint { + ($(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?) => { + declare_tool_lint! { + $(#[$attr])* pub rustdoc::$name, $level, $descr + } + } +} + +declare_rustdoc_lint! { /// The `broken_intra_doc_links` lint detects failures in resolving /// intra-doc link targets. This is a `rustdoc` only lint, see the /// documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links - pub rustdoc::BROKEN_INTRA_DOC_LINKS, + BROKEN_INTRA_DOC_LINKS, Warn, "failures in resolving intra-doc link targets" } -declare_tool_lint! { +declare_rustdoc_lint! { /// This is a subset of `broken_intra_doc_links` that warns when linking from /// a public item to a private one. This is a `rustdoc` only lint, see the /// documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links - pub rustdoc::PRIVATE_INTRA_DOC_LINKS, + PRIVATE_INTRA_DOC_LINKS, Warn, "linking from a public item to a private one" } -declare_tool_lint! { +declare_rustdoc_lint! { /// The `invalid_codeblock_attributes` lint detects code block attributes /// in documentation examples that have potentially mis-typed values. This /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes - pub rustdoc::INVALID_CODEBLOCK_ATTRIBUTES, + INVALID_CODEBLOCK_ATTRIBUTES, Warn, "codeblock attribute looks a lot like a known one" } -declare_tool_lint! { +declare_rustdoc_lint! { /// The `missing_doc_code_examples` lint detects publicly-exported items /// without code samples in their documentation. This is a `rustdoc` only /// lint, see the documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples - pub rustdoc::MISSING_DOC_CODE_EXAMPLES, + MISSING_DOC_CODE_EXAMPLES, Allow, "detects publicly-exported items without code samples in their documentation" } -declare_tool_lint! { +declare_rustdoc_lint! { /// The `private_doc_tests` lint detects code samples in docs of private /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see /// the documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests - pub rustdoc::PRIVATE_DOC_TESTS, + PRIVATE_DOC_TESTS, Allow, "detects code samples in docs of private items not documented by rustdoc" } -declare_tool_lint! { +declare_rustdoc_lint! { /// The `invalid_html_tags` lint detects invalid HTML tags. This is a /// `rustdoc` only lint, see the documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags - pub rustdoc::INVALID_HTML_TAGS, + INVALID_HTML_TAGS, Allow, "detects invalid HTML tags in doc comments" } -declare_tool_lint! { +declare_rustdoc_lint! { /// The `non_autolinks` lint detects when a URL could be written using /// only angle brackets. This is a `rustdoc` only lint, see the /// documentation in the [rustdoc book]. /// /// [rustdoc book]: ../../../rustdoc/lints.html#non_autolinks - pub rustdoc::NON_AUTOLINKS, + NON_AUTOLINKS, Warn, "detects URLs that could be written using only angle brackets" } From e8ddfda8138d9c282eee16cfae892ed232d8b422 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 17 Jan 2021 18:52:19 -0500 Subject: [PATCH 33/67] Improve error messages - Use `register_renamed` when rustdoc is running so the lint will still be active and use a structured suggestion - Test the behavior for rustc, not just for rustdoc (because it differs) --- compiler/rustc_lint/src/lib.rs | 4 ++++ src/librustdoc/lint.rs | 4 ++++ src/test/rustdoc-ui/unknown-renamed-lints.rs | 8 +++----- .../rustdoc-ui/unknown-renamed-lints.stderr | 8 ++++---- src/test/ui/lint/rustdoc-renamed.rs | 14 +++++++++++++ src/test/ui/lint/rustdoc-renamed.stderr | 20 +++++++++++++++++++ 6 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/lint/rustdoc-renamed.rs create mode 100644 src/test/ui/lint/rustdoc-renamed.stderr diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 67c0e999f5518..86ad73d482f24 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -339,6 +339,10 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { // FIXME: maybe we could get `register_renamed` to work for tool lints? store.register_removed(rustdoc_lint, &format!("use `rustdoc::{}` instead", rustdoc_lint)); } + store.register_removed( + "intra_doc_link_resolution_failure", + "use `rustdoc::broken_intra_doc_links` instead", + ); store.register_removed("unknown_features", "replaced by an error"); store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 013b7ead5c7c9..7d95561d039f9 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -167,6 +167,10 @@ crate fn register_lints(_sess: &Session, lint_store: &mut LintStore) { None, RUSTDOC_LINTS.iter().map(|&lint| LintId::of(lint)).collect(), ); + for lint in &*RUSTDOC_LINTS { + let name = lint.name_lower(); + lint_store.register_renamed(&name.replace("rustdoc::", ""), &name); + } lint_store .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links"); } diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.rs b/src/test/rustdoc-ui/unknown-renamed-lints.rs index e2238a4004c1b..d2c78bc477410 100644 --- a/src/test/rustdoc-ui/unknown-renamed-lints.rs +++ b/src/test/rustdoc-ui/unknown-renamed-lints.rs @@ -7,13 +7,11 @@ #![deny(rustdoc::x)] //~^ ERROR unknown lint: `rustdoc::x` #![deny(intra_doc_link_resolution_failure)] -//~^ ERROR has been renamed +//~^ ERROR renamed to `rustdoc::broken_intra_doc_links` -// This would ideally say 'renamed to rustdoc::non_autolinks', but this is close enough. #![deny(non_autolinks)] -//~^ ERROR has been removed: use `rustdoc::non_autolinks` instead [renamed_and_removed_lints] +//~^ ERROR renamed to `rustdoc::non_autolinks` -// This doesn't give you the right code directly, but at least points you on the -// right path. +// Explicitly don't try to handle this case, it was never valid #![deny(rustdoc::intra_doc_link_resolution_failure)] //~^ ERROR unknown lint diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.stderr b/src/test/rustdoc-ui/unknown-renamed-lints.stderr index 1a45f68ae810f..0f31673fb47f2 100644 --- a/src/test/rustdoc-ui/unknown-renamed-lints.stderr +++ b/src/test/rustdoc-ui/unknown-renamed-lints.stderr @@ -28,14 +28,14 @@ note: the lint level is defined here LL | #![deny(renamed_and_removed_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: lint `non_autolinks` has been removed: use `rustdoc::non_autolinks` instead - --> $DIR/unknown-renamed-lints.rs:13:9 +error: lint `non_autolinks` has been renamed to `rustdoc::non_autolinks` + --> $DIR/unknown-renamed-lints.rs:12:9 | LL | #![deny(non_autolinks)] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ help: use the new name: `rustdoc::non_autolinks` error: unknown lint: `rustdoc::intra_doc_link_resolution_failure` - --> $DIR/unknown-renamed-lints.rs:18:9 + --> $DIR/unknown-renamed-lints.rs:16:9 | LL | #![deny(rustdoc::intra_doc_link_resolution_failure)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/rustdoc-renamed.rs b/src/test/ui/lint/rustdoc-renamed.rs new file mode 100644 index 0000000000000..71e88bd7f54a5 --- /dev/null +++ b/src/test/ui/lint/rustdoc-renamed.rs @@ -0,0 +1,14 @@ +#![crate_type = "lib"] + +#![deny(unknown_lints)] +#![deny(renamed_and_removed_lints)] +//~^ NOTE lint level is defined + +// both allowed, since the compiler doesn't yet know what rustdoc lints are valid +#![deny(rustdoc::x)] +#![deny(rustdoc::intra_doc_link_resolution_failure)] + +#![deny(intra_doc_link_resolution_failure)] +//~^ ERROR removed: use `rustdoc::broken_intra_doc_links` +#![deny(non_autolinks)] +//~^ ERROR removed: use `rustdoc::non_autolinks` diff --git a/src/test/ui/lint/rustdoc-renamed.stderr b/src/test/ui/lint/rustdoc-renamed.stderr new file mode 100644 index 0000000000000..a7fe3e29d5be0 --- /dev/null +++ b/src/test/ui/lint/rustdoc-renamed.stderr @@ -0,0 +1,20 @@ +error: lint `intra_doc_link_resolution_failure` has been removed: use `rustdoc::broken_intra_doc_links` instead + --> $DIR/rustdoc-renamed.rs:11:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/rustdoc-renamed.rs:4:9 + | +LL | #![deny(renamed_and_removed_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lint `non_autolinks` has been removed: use `rustdoc::non_autolinks` instead + --> $DIR/rustdoc-renamed.rs:13:9 + | +LL | #![deny(non_autolinks)] + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 0517ea7cdc0b916b2ab2e7909cbfac355c6b1e1d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 18 Jan 2021 01:14:01 -0500 Subject: [PATCH 34/67] Address review comments - Move MISSING_CRATE_LEVEL_DOCS to rustdoc directly - Update documentation This also takes the opportunity to make the `no-crate-level-doc-lint` test more specific. --- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint_defs/src/builtin.rs | 12 ------- src/doc/rustdoc/src/lints.md | 35 +++++++++++-------- src/librustdoc/core.rs | 5 ++- src/librustdoc/lint.rs | 12 +++++++ src/test/rustdoc-ui/check.stderr | 13 ++++++- .../rustdoc-ui/no-crate-level-doc-lint.rs | 4 ++- .../rustdoc-ui/no-crate-level-doc-lint.stderr | 6 ++-- 8 files changed, 54 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 86ad73d482f24..a15a972cce721 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -329,6 +329,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { const RUSTDOC_LINTS: &[&str] = &[ "broken_intra_doc_links", "private_intra_doc_links", + "missing_crate_level_docs", "missing_doc_code_examples", "private_doc_tests", "invalid_codeblock_attributes", diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 53bb0fb28a65b..12d849e3b9466 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1875,17 +1875,6 @@ declare_lint! { "detects labels that are never used" } -declare_lint! { - /// The `missing_crate_level_docs` lint detects if documentation is - /// missing at the crate root. This is a `rustdoc` only lint, see the - /// documentation in the [rustdoc book]. - /// - /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs - pub MISSING_CRATE_LEVEL_DOCS, - Allow, - "detects crates with no crate-level documentation" -} - declare_lint! { /// The `where_clauses_object_safety` lint detects for [object safety] of /// [where clauses]. @@ -2944,7 +2933,6 @@ declare_lint_pass! { ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, UNSTABLE_NAME_COLLISIONS, IRREFUTABLE_LET_PATTERNS, - MISSING_CRATE_LEVEL_DOCS, WHERE_CLAUSES_OBJECT_SAFETY, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, MACRO_USE_EXTERN_CRATE, diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index cce3623dc8f49..174db711bcee7 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -4,12 +4,13 @@ can use them like any other lints by doing this: ```rust -#![allow(missing_docs)] // allows the lint, no diagnostics will be reported -#![warn(missing_docs)] // warn if there are missing docs -#![deny(missing_docs)] // error if there are missing docs -# //! Crate docs. +#![allow(rustdoc::broken_intra_doc_links)] // allows the lint, no diagnostics will be reported +#![warn(rustdoc::broken_intra_doc_links)] // warn if there are broken intra-doc links +#![deny(rustdoc::broken_intra_doc_links)] // error if there are broken intra-doc links ``` +Note that, except for `missing_docs`, these lints are only available when running `rustdoc`, not `rustc`. + Here is the list of the lints provided by `rustdoc`: ## broken_intra_doc_links @@ -51,7 +52,7 @@ warning: `Foo` is both an enum and a function 1 | /// [`Foo`] | ^^^^^ ambiguous link | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default help: to link to the enum, prefix with the item type | 1 | /// [`enum@Foo`] @@ -83,7 +84,7 @@ warning: public documentation for `public` links to private item `private` 1 | /// [private] | ^^^^^^^ this item is private | - = note: `#[warn(private_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` ``` @@ -97,7 +98,7 @@ warning: public documentation for `public` links to private item `private` 1 | /// [private] | ^^^^^^^ this item is private | - = note: `#[warn(private_intra_doc_links)]` on by default + = note: `#[warn(rustdoc::private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without ``` @@ -125,13 +126,15 @@ warning: missing documentation for a function | ^^^^^^^^^^^^^^^^^^^^^ ``` +Note that unlike other rustdoc lints, this lint is also available from `rustc` directly. + ## missing_crate_level_docs This lint is **allowed by default**. It detects if there is no documentation at the crate root. For example: ```rust -#![warn(missing_crate_level_docs)] +#![warn(rustdoc::missing_crate_level_docs)] ``` This will generate the following warning: @@ -155,7 +158,7 @@ This lint is **allowed by default** and is **nightly-only**. It detects when a d is missing a code example. For example: ```rust -#![warn(missing_doc_code_examples)] +#![warn(rustdoc::missing_doc_code_examples)] /// There is no code example! pub fn no_code_example() {} @@ -191,7 +194,7 @@ This lint is **allowed by default**. It detects documentation tests when they are on a private item. For example: ```rust -#![warn(private_doc_tests)] +#![warn(rustdoc::private_doc_tests)] mod foo { /// private doc test @@ -245,7 +248,7 @@ warning: unknown attribute `should-panic`. Did you mean `should_panic`? 5 | | /// ``` | |_______^ | - = note: `#[warn(invalid_codeblock_attributes)]` on by default + = note: `#[warn(rustdoc::invalid_codeblock_attributes)]` on by default = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running ``` @@ -258,7 +261,7 @@ This lint is **allowed by default** and is **nightly-only**. It detects unclosed or invalid HTML tags. For example: ```rust -#![warn(invalid_html_tags)] +#![warn(rustdoc::invalid_html_tags)] ///

/// @@ -275,7 +278,11 @@ warning: unopened HTML tag `script` 2 | | /// | |_____________^ | - = note: `#[warn(invalid_html_tags)]` on by default + note: the lint level is defined here + --> foo.rs:1:9 + | +1 | #![warn(rustdoc::invalid_html_tags)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unclosed HTML tag `h1` --> foo.rs:1:1 @@ -310,7 +317,7 @@ warning: this URL is not a hyperlink 1 | /// http://example.org | ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `` | - = note: `#[warn(non_autolinks)]` on by default + = note: `#[warn(rustdoc::non_autolinks)]` on by default warning: unneeded long form for URL --> foo.rs:2:5 diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 5313f8553a894..9580a6d1ddc82 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -260,9 +260,8 @@ crate fn create_config( // By default, rustdoc ignores all lints. // Specifically unblock lints relevant to documentation or the lint machinery itself. let mut lints_to_show = vec![ - // it's unclear whether these should be part of rustdoc directly + // it's unclear whether this should be part of rustdoc directly (#77364) rustc_lint::builtin::MISSING_DOCS.name.to_string(), - rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name.to_string(), // these are definitely not part of rustdoc, but we want to warn on them anyway. rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(), rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(), @@ -482,7 +481,7 @@ crate fn run_global_ctxt( let help = "The following guide may be of use:\n\ https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html"; tcx.struct_lint_node( - rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS, + crate::lint::MISSING_CRATE_LEVEL_DOCS, ctxt.as_local_hir_id(m.def_id).unwrap(), |lint| { let mut diag = diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 7d95561d039f9..e8806c1b6d787 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -104,6 +104,17 @@ declare_rustdoc_lint! { "codeblock attribute looks a lot like a known one" } +declare_rustdoc_lint! { + /// The `missing_crate_level_docs` lint detects if documentation is + /// missing at the crate root. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs + MISSING_CRATE_LEVEL_DOCS, + Allow, + "detects crates with no crate-level documentation" +} + declare_rustdoc_lint! { /// The `missing_doc_code_examples` lint detects publicly-exported items /// without code samples in their documentation. This is a `rustdoc` only @@ -156,6 +167,7 @@ crate static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS, NON_AUTOLINKS, + MISSING_CRATE_LEVEL_DOCS, ] }); diff --git a/src/test/rustdoc-ui/check.stderr b/src/test/rustdoc-ui/check.stderr index 3c29a45a64a98..e6ba9df9b0555 100644 --- a/src/test/rustdoc-ui/check.stderr +++ b/src/test/rustdoc-ui/check.stderr @@ -21,6 +21,17 @@ warning: missing documentation for a function LL | pub fn foo() {} | ^^^^^^^^^^^^ +warning: no documentation found for this crate's top-level module + | +note: the lint level is defined here + --> $DIR/check.rs:7:9 + | +LL | #![warn(rustdoc)] + | ^^^^^^^ + = note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc)]` + = help: The following guide may be of use: + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html + warning: missing code example in this documentation --> $DIR/check.rs:4:1 | @@ -45,5 +56,5 @@ warning: missing code example in this documentation LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ -warning: 4 warnings emitted +warning: 5 warnings emitted diff --git a/src/test/rustdoc-ui/no-crate-level-doc-lint.rs b/src/test/rustdoc-ui/no-crate-level-doc-lint.rs index 152a7cd88bcb1..3939ec6827ade 100644 --- a/src/test/rustdoc-ui/no-crate-level-doc-lint.rs +++ b/src/test/rustdoc-ui/no-crate-level-doc-lint.rs @@ -1,3 +1,5 @@ -#![deny(missing_crate_level_docs)] +// error-pattern: no documentation found +#![deny(rustdoc::missing_crate_level_docs)] +//^~ NOTE defined here pub fn foo() {} diff --git a/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr b/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr index 6e7e2fb3eb73f..55ead1a55cfcd 100644 --- a/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr +++ b/src/test/rustdoc-ui/no-crate-level-doc-lint.stderr @@ -1,10 +1,10 @@ error: no documentation found for this crate's top-level module | note: the lint level is defined here - --> $DIR/no-crate-level-doc-lint.rs:1:9 + --> $DIR/no-crate-level-doc-lint.rs:2:9 | -LL | #![deny(missing_crate_level_docs)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustdoc::missing_crate_level_docs)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: The following guide may be of use: https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html From c7535d13617078029f870a5ccc9258b42dc360b8 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 18 Jan 2021 22:24:16 -0500 Subject: [PATCH 35/67] Update comments Note that the FIXME was removed because this can't be fixed, `register_renamed` calls LintId::of and there's no LintId for rustdoc lints when rustc is running. --- compiler/rustc_lint/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a15a972cce721..547779dd6856a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -325,7 +325,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use - // `register_renamed` explicitly. + // `register_removed` explicitly. const RUSTDOC_LINTS: &[&str] = &[ "broken_intra_doc_links", "private_intra_doc_links", @@ -337,7 +337,6 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { "non_autolinks", ]; for rustdoc_lint in RUSTDOC_LINTS { - // FIXME: maybe we could get `register_renamed` to work for tool lints? store.register_removed(rustdoc_lint, &format!("use `rustdoc::{}` instead", rustdoc_lint)); } store.register_removed( From 75efb6efa34adf6436b4cb687f3a57f29bb635c7 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 28 Feb 2021 00:49:15 -0500 Subject: [PATCH 36/67] Test that using the previous lint names still applies the lint --- .../rustdoc-ui/renamed-lint-still-applies.rs | 5 ++++ .../renamed-lint-still-applies.stderr | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/test/rustdoc-ui/renamed-lint-still-applies.rs create mode 100644 src/test/rustdoc-ui/renamed-lint-still-applies.stderr diff --git a/src/test/rustdoc-ui/renamed-lint-still-applies.rs b/src/test/rustdoc-ui/renamed-lint-still-applies.rs new file mode 100644 index 0000000000000..6d4bad16aadc2 --- /dev/null +++ b/src/test/rustdoc-ui/renamed-lint-still-applies.rs @@ -0,0 +1,5 @@ +// compile-args: --crate-type lib +#![deny(broken_intra_doc_links)] +//~^ WARNING renamed +//! [x] +//~^ ERROR unresolved link diff --git a/src/test/rustdoc-ui/renamed-lint-still-applies.stderr b/src/test/rustdoc-ui/renamed-lint-still-applies.stderr new file mode 100644 index 0000000000000..e14cbfa1726c3 --- /dev/null +++ b/src/test/rustdoc-ui/renamed-lint-still-applies.stderr @@ -0,0 +1,23 @@ +warning: lint `broken_intra_doc_links` has been renamed to `rustdoc::broken_intra_doc_links` + --> $DIR/renamed-lint-still-applies.rs:2:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links` + | + = note: `#[warn(renamed_and_removed_lints)]` on by default + +error: unresolved link to `x` + --> $DIR/renamed-lint-still-applies.rs:4:6 + | +LL | //! [x] + | ^ no item named `x` in scope + | +note: the lint level is defined here + --> $DIR/renamed-lint-still-applies.rs:2:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to previous error; 1 warning emitted + From 768d5e950953738a54480e530341964838d29da2 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Fri, 19 Feb 2021 17:22:30 -0800 Subject: [PATCH 37/67] Load rustdoc's JS search index on-demand. Instead of being loaded on every page, the JS search index is now loaded when either (a) there is a `?search=` param, or (b) the search input is focused. This saves both CPU and bandwidth. As of Feb 2021, https://doc.rust-lang.org/search-index1.50.0.js is 273,838 bytes gzipped or 2,544,939 bytes uncompressed. Evaluating it takes 445 ms of CPU time in Chrome 88 on a i7-10710U CPU (out of a total ~2,100 ms page reload). Generate separate JS file with crate names. This is much smaller than the full search index, and is used in the "hot path" to draw the page. In particular it's used to crate the dropdown for the search bar, and to append a list of crates to the sidebar (on some pages). Skip early search that can bypass 500ms timeout. This was occurring when someone had typed some text during the load of search-index.js. Their query was usually not ready to execute, and the search itself is fairly expensive, delaying the overall load, which delayed the input / keyup events, which delayed eventually executing the query. --- src/librustdoc/html/layout.rs | 5 +- src/librustdoc/html/render/mod.rs | 17 +++--- src/librustdoc/html/static/main.js | 98 +++++++++++++++++------------- 3 files changed, 69 insertions(+), 51 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index e5a686bd07d07..855934ef4d430 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -58,6 +58,7 @@ crate fn render( {style_files}\ \ \ + \ \ {css_extension}\ {favicon}\ @@ -112,10 +113,10 @@ crate fn render(
\
\ {after_content}\ -
+
\ {extra_scripts}\ - \ \ ", css_extension = if layout.css_file_extension.is_some() { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 58e9e41e6a53c..dd531f1510220 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1039,10 +1039,12 @@ themePicker.onblur = handleThemeButtonsBlur; cx.shared.fs.write(&dst, v.as_bytes())?; } - // Update the search index + // Update the search index and crate list. let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix)); let (mut all_indexes, mut krates) = try_err!(collect_json(&dst, &krate.name.as_str()), &dst); all_indexes.push(search_index); + krates.push(krate.name.to_string()); + krates.sort(); // Sort the indexes by crate so the file will be generated identically even // with rustdoc running in parallel. @@ -1050,11 +1052,15 @@ themePicker.onblur = handleThemeButtonsBlur; { let mut v = String::from("var searchIndex = JSON.parse('{\\\n"); v.push_str(&all_indexes.join(",\\\n")); - // "addSearchOptions" has to be called first so the crate filtering can be set before the - // search might start (if it's set into the URL for example). - v.push_str("\\\n}');\naddSearchOptions(searchIndex);initSearch(searchIndex);"); + v.push_str("\\\n}');\ninitSearch(searchIndex);"); cx.shared.fs.write(&dst, &v)?; } + + let crate_list_dst = cx.dst.join(&format!("crates{}.js", cx.shared.resource_suffix)); + let crate_list = + format!("window.ALL_CRATES = [{}];", krates.iter().map(|k| format!("\"{}\"", k)).join(",")); + cx.shared.fs.write(&crate_list_dst, &crate_list)?; + if options.enable_index_page { if let Some(index_page) = options.index_page.clone() { let mut md_opts = options.clone(); @@ -1076,9 +1082,6 @@ themePicker.onblur = handleThemeButtonsBlur; extra_scripts: &[], static_extra_scripts: &[], }; - krates.push(krate.name.to_string()); - krates.sort(); - krates.dedup(); let content = format!( "

\ diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 76449a171d7cc..89b1362b32b63 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -42,6 +42,7 @@ if (!DOMTokenList.prototype.remove) { if (rustdocVars) { window.rootPath = rustdocVars.attributes["data-root-path"].value; window.currentCrate = rustdocVars.attributes["data-current-crate"].value; + window.searchJS = rustdocVars.attributes["data-search-js"].value; } var sidebarVars = document.getElementById("sidebar-vars"); if (sidebarVars) { @@ -1922,8 +1923,8 @@ function defocusSearchBar() { return searchWords; } - function startSearch() { - var callback = function() { + function registerSearchEvents() { + var searchAfter500ms = function() { clearInputTimeout(); if (search_input.value.length === 0) { if (browserSupportsHistoryApi()) { @@ -1935,8 +1936,8 @@ function defocusSearchBar() { searchTimeout = setTimeout(search, 500); } }; - search_input.onkeyup = callback; - search_input.oninput = callback; + search_input.onkeyup = searchAfter500ms; + search_input.oninput = searchAfter500ms; document.getElementsByClassName("search-form")[0].onsubmit = function(e) { e.preventDefault(); clearInputTimeout(); @@ -1999,7 +2000,6 @@ function defocusSearchBar() { } }); } - search(); // This is required in firefox to avoid this problem: Navigating to a search result // with the keyboard, hitting enter, and then hitting back would take you back to @@ -2017,8 +2017,14 @@ function defocusSearchBar() { } index = buildIndex(rawSearchIndex); - startSearch(); + registerSearchEvents(); + // If there's a search term in the URL, execute the search now. + if (getQueryStringParams().search) { + search(); + } + }; + function addSidebarCrates(crates) { // Draw a convenient sidebar of known crates if we have a listing if (window.rootPath === "../" || window.rootPath === "./") { var sidebar = document.getElementsByClassName("sidebar-elems")[0]; @@ -2029,14 +2035,6 @@ function defocusSearchBar() { var ul = document.createElement("ul"); div.appendChild(ul); - var crates = []; - for (var crate in rawSearchIndex) { - if (!hasOwnProperty(rawSearchIndex, crate)) { - continue; - } - crates.push(crate); - } - crates.sort(); for (var i = 0; i < crates.length; ++i) { var klass = "crate"; if (window.rootPath !== "./" && crates[i] === window.currentCrate) { @@ -2044,9 +2042,6 @@ function defocusSearchBar() { } var link = document.createElement("a"); link.href = window.rootPath + crates[i] + "/index.html"; - // The summary in the search index has HTML, so we need to - // dynamically render it as plaintext. - link.title = convertHTMLToPlaintext(rawSearchIndex[crates[i]].doc); link.className = klass; link.textContent = crates[i]; @@ -2057,7 +2052,7 @@ function defocusSearchBar() { sidebar.appendChild(div); } } - }; + } /** * Convert HTML to plaintext: @@ -2862,37 +2857,18 @@ function defocusSearchBar() { } } - window.addSearchOptions = function(crates) { + function addSearchOptions(crates) { var elem = document.getElementById("crate-search"); if (!elem) { enableSearchInput(); return; } - var crates_text = []; - if (Object.keys(crates).length > 1) { - for (var crate in crates) { - if (hasOwnProperty(crates, crate)) { - crates_text.push(crate); - } - } - } - crates_text.sort(function(a, b) { - var lower_a = a.toLowerCase(); - var lower_b = b.toLowerCase(); - - if (lower_a < lower_b) { - return -1; - } else if (lower_a > lower_b) { - return 1; - } - return 0; - }); var savedCrate = getSettingValue("saved-filter-crate"); - for (var i = 0, len = crates_text.length; i < len; ++i) { + for (var i = 0, len = crates.length; i < len; ++i) { var option = document.createElement("option"); - option.value = crates_text[i]; - option.innerText = crates_text[i]; + option.value = crates[i]; + option.innerText = crates[i]; elem.appendChild(option); // Set the crate filter from saved storage, if the current page has the saved crate // filter. @@ -2900,7 +2876,7 @@ function defocusSearchBar() { // If not, ignore the crate filter -- we want to support filtering for crates on sites // like doc.rust-lang.org where the crates may differ from page to page while on the // same domain. - if (crates_text[i] === savedCrate) { + if (crates[i] === savedCrate) { elem.value = savedCrate; } } @@ -2969,6 +2945,44 @@ function defocusSearchBar() { buildHelperPopup = function() {}; } + function loadScript(url) { + var script = document.createElement('script'); + script.src = url; + document.head.append(script); + } + + function setupSearchLoader() { + var searchLoaded = false; + function loadSearch() { + if (!searchLoaded) { + searchLoaded = true; + loadScript(window.searchJS); + } + } + + // `crates{version}.js` should always be loaded before this script, so we can use it safely. + addSearchOptions(window.ALL_CRATES); + addSidebarCrates(window.ALL_CRATES); + + search_input.addEventListener("focus", function() { + search_input.origPlaceholder = search_input.placeholder; + search_input.placeholder = "Type your search here."; + loadSearch(); + }); + search_input.addEventListener("blur", function() { + search_input.placeholder = search_input.origPlaceholder; + }); + enableSearchInput(); + + var crateSearchDropDown = document.getElementById("crate-search"); + crateSearchDropDown.addEventListener("focus", loadSearch); + var params = getQueryStringParams(); + if (params.search !== undefined) { + loadSearch(); + } + } + onHashChange(null); window.onhashchange = onHashChange; + setupSearchLoader(); }()); From 9c4e3af39d5e93b2976afa8062ee5c705ba589c5 Mon Sep 17 00:00:00 2001 From: Waffle Date: Wed, 3 Mar 2021 01:00:59 +0300 Subject: [PATCH 38/67] Add test that Vec::spare_capacity_mut doesn't invalidate pointers --- library/alloc/tests/lib.rs | 1 + library/alloc/tests/vec.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index dd98f806451d8..d40496bfaaba7 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -21,6 +21,7 @@ #![feature(vecdeque_binary_search)] #![feature(slice_group_by)] #![feature(vec_extend_from_within)] +#![feature(vec_spare_capacity)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 2969da58d4268..fab450285854d 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1691,6 +1691,10 @@ fn test_stable_pointers() { next_then_drop(v.splice(5..6, vec![1; 10].into_iter().filter(|_| true))); // lower bound not exact assert_eq!(*v0, 13); + // spare_capacity_mut + v.spare_capacity_mut(); + assert_eq!(*v0, 13); + // Smoke test that would fire even outside Miri if an actual relocation happened. *v0 -= 13; assert_eq!(v[0], 0); From a1835bcb01fc345653fd9e9ce02b0d103032c58d Mon Sep 17 00:00:00 2001 From: Waffle Date: Wed, 3 Mar 2021 01:04:20 +0300 Subject: [PATCH 39/67] Make Vec::split_at_spare_mut impl safer & simplier --- library/alloc/src/vec/mod.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e5545d2a77ff7..ff401b33832ce 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1944,20 +1944,16 @@ impl Vec { #[unstable(feature = "vec_split_at_spare", issue = "81944")] #[inline] pub fn split_at_spare_mut(&mut self) -> (&mut [T], &mut [MaybeUninit]) { - let ptr = self.as_mut_ptr(); - - // SAFETY: - // - `ptr` is guaranteed to be in bounds for `capacity` elements - // - `len` is guaranteed to less or equal to `capacity` - // - `MaybeUninit` has the same layout as `T` - let spare_ptr = unsafe { ptr.cast::>().add(self.len) }; + let Range { start: ptr, end: spare_ptr } = self.as_mut_ptr_range(); + let spare_ptr = spare_ptr.cast::>(); + let spare_len = self.buf.capacity() - self.len; // SAFETY: // - `ptr` is guaranteed to be valid for `len` elements - // - `spare_ptr` is offseted from `ptr` by `len`, so it doesn't overlap `initialized` slice + // - `spare_ptr` is pointing one element past the buffer, so it doesn't overlap with `initialized` slice unsafe { let initialized = slice::from_raw_parts_mut(ptr, self.len); - let spare = slice::from_raw_parts_mut(spare_ptr, self.buf.capacity() - self.len); + let spare = slice::from_raw_parts_mut(spare_ptr, spare_len); (initialized, spare) } From d3e7ffa7f548801d4a5784d314aabdafe9186af7 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Fri, 19 Feb 2021 17:54:41 -0800 Subject: [PATCH 40/67] Improve page load performance in rustdoc. Add font-display: swap. Per https://web.dev/font-display/, this prevents "flash of invisible text" during load by using a system font until the custom font is available. I've noticed this flash of invisible text occasionally when reading Rust docs. Add an explicit height to icons (which already had an explicit width) to allow browsers to lay out the page more accurately before the icons have been loaded. https://web.dev/optimize-cls/. Add min-width: 115px to the crate search dropdown. When the HTML first loads, this dropdown includes only the text "All crates." Later, JS loads the items underneath it, some of which are wider. That causes the dropdown to get wider, causing a distracting reflow. This sets a min-width based on the size that the dropdown eventually becomes based on the crates on doc.rust-lang.org, reducing page movement during load. --- src/doc/rust.css | 6 ++++++ src/librustdoc/html/layout.rs | 4 ++-- src/librustdoc/html/static/rustdoc.css | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/doc/rust.css b/src/doc/rust.css index a92d4ff54db83..ff18e1a8f51cc 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -3,30 +3,35 @@ font-style: normal; font-weight: 400; src: local('Fira Sans'), url("FiraSans-Regular.woff") format('woff'); + font-display: swap; } @font-face { font-family: 'Fira Sans'; font-style: normal; font-weight: 500; src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff'); + font-display: swap; } @font-face { font-family: 'Source Serif Pro'; font-style: normal; font-weight: 400; src: local('Source Serif Pro'), url("SourceSerifPro-Regular.ttf.woff") format('woff'); + font-display: swap; } @font-face { font-family: 'Source Serif Pro'; font-style: italic; font-weight: 400; src: url("SourceSerifPro-It.ttf.woff") format('woff'); + font-display: swap; } @font-face { font-family: 'Source Serif Pro'; font-style: normal; font-weight: 700; src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.ttf.woff") format('woff'); + font-display: swap; } @font-face { font-family: 'Source Code Pro'; @@ -35,6 +40,7 @@ /* 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'); + font-display: swap; } *:not(body) { diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index e5a686bd07d07..64b209a46c01d 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -82,7 +82,7 @@ crate fn render(
\ \
\ @@ -102,7 +102,7 @@ crate fn render( \ \"Change\ \
\ diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index e3d63fa2308e2..7da18409d5e0e 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -6,6 +6,7 @@ src: local('Fira Sans'), url("FiraSans-Regular.woff2") format("woff2"), url("FiraSans-Regular.woff") format('woff'); + font-display: swap; } @font-face { font-family: 'Fira Sans'; @@ -14,6 +15,7 @@ src: local('Fira Sans Medium'), url("FiraSans-Medium.woff2") format("woff2"), url("FiraSans-Medium.woff") format('woff'); + font-display: swap; } /* See SourceSerifPro-LICENSE.txt for the Source Serif Pro license. */ @@ -22,18 +24,21 @@ font-style: normal; font-weight: 400; src: local('Source Serif Pro'), url("SourceSerifPro-Regular.ttf.woff") format('woff'); + font-display: swap; } @font-face { font-family: 'Source Serif Pro'; font-style: italic; font-weight: 400; src: local('Source Serif Pro Italic'), url("SourceSerifPro-It.ttf.woff") format('woff'); + font-display: swap; } @font-face { font-family: 'Source Serif Pro'; font-style: normal; font-weight: 700; src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.ttf.woff") format('woff'); + font-display: swap; } /* See SourceCodePro-LICENSE.txt for the Source Code Pro license. */ @@ -44,12 +49,14 @@ /* 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'); + font-display: swap; } @font-face { font-family: 'Source Code Pro'; font-style: normal; font-weight: 600; src: url("SourceCodePro-Semibold.woff") format('woff'); + font-display: swap; } * { @@ -684,6 +691,7 @@ a { width: calc(100% - 63px); } #crate-search { + min-width: 115px; margin-top: 5px; padding: 6px; padding-right: 19px; From f9cfe1583b18052bc5f42d92e8973e18ba404b19 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Tue, 2 Mar 2021 18:27:34 -0800 Subject: [PATCH 41/67] Use Arial as fallback font instead of sans-serif. On most platforms and browsers, `sans-serif` is equivalent to Arial. However, on Firefox on Ubuntu (and possibly other Linuxes), `sans-serif` is DejaVu Sans, a much wider font. This creates a larger shift in text when the custom fonts finally load. Arial is a web-safe font, and specifying it explicitly gives us more cross-platform consistency, as well as reducing the layout shift that happens when fonts load. --- src/librustdoc/html/static/rustdoc.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 7da18409d5e0e..94c231cb33a8b 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -136,7 +136,7 @@ h1, h2, h3, h4, #source-sidebar, #sidebar-toggle, /* This selector is for the items listed in the "all items" page. */ #main > ul.docblock > li > a { - font-family: "Fira Sans", sans-serif; + font-family: "Fira Sans", Arial; } .content ul.crate a.crate { @@ -482,7 +482,7 @@ h4 > code, h3 > code, .invisible > code { } #main > .since { top: inherit; - font-family: "Fira Sans", sans-serif; + font-family: "Fira Sans", Arial; } .content table:not(.table-display) { @@ -1301,7 +1301,7 @@ h4 > .notable-traits { .help-button { right: 30px; - font-family: "Fira Sans",sans-serif; + font-family: "Fira Sans", Arial; text-align: center; font-size: 17px; } From 040735c110026bbd494a23c86182ebda201d720b Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 5 Jan 2021 10:07:50 +0100 Subject: [PATCH 42/67] First version of noop-lint --- compiler/rustc_lint/src/lib.rs | 3 + compiler/rustc_lint/src/noop_method_call.rs | 71 +++++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/clone.rs | 2 + 4 files changed, 77 insertions(+) create mode 100644 compiler/rustc_lint/src/noop_method_call.rs diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 638b73c27a8d7..b0c22154c0b5b 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -57,6 +57,7 @@ mod methods; mod non_ascii_idents; mod non_fmt_panic; mod nonstandard_style; +mod noop_method_call; mod passes; mod redundant_semicolon; mod traits; @@ -83,6 +84,7 @@ use methods::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; use nonstandard_style::*; +use noop_method_call::*; use redundant_semicolon::*; use traits::*; use types::*; @@ -170,6 +172,7 @@ macro_rules! late_lint_passes { DropTraitConstraints: DropTraitConstraints, TemporaryCStringAsPtr: TemporaryCStringAsPtr, NonPanicFmt: NonPanicFmt, + NoopMethodCall: NoopMethodCall, ] ); }; diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs new file mode 100644 index 0000000000000..098c50d5abe19 --- /dev/null +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -0,0 +1,71 @@ +use crate::context::LintContext; +use crate::rustc_middle::ty::TypeFoldable; +use crate::LateContext; +use crate::LateLintPass; +use rustc_hir::def::DefKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_middle::ty; +use rustc_span::symbol::sym; + +declare_lint! { + /// The `noop_method_call` lint detects specific calls to noop methods + /// such as a calling `<&T as Clone>::clone` where `T: !Clone`. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// struct Foo; + /// let foo = &Foo; + /// let clone: &Foo = foo.clone(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Some method calls are noops meaning that they do nothing. Usually such methods + /// are the result of blanket implementations that happen to create some method invocations + /// that end up not doing anything. For instance, `Clone` is implemented on all `&T`, but + /// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything + /// as references are copy. This lint detects these calls and warns the user about them. + pub NOOP_METHOD_CALL, + Warn, + "detects the use of well-known noop methods" +} + +declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); + +impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + // We only care about method calls + if let ExprKind::MethodCall(..) = expr.kind { + // Get the `DefId` only when dealing with an `AssocFn` + if let Some((DefKind::AssocFn, did)) = + cx.typeck_results().type_dependent_def(expr.hir_id) + { + // Check that we're dealing with a trait method + if let Some(trait_id) = cx.tcx.trait_of_item(did) { + let substs = cx.typeck_results().node_substs(expr.hir_id); + // We can't resolve on types that recursively require monomorphization, + // so check that we don't need to perfom substitution + if !substs.needs_subst() { + let param_env = cx.tcx.param_env(trait_id); + // Resolve the trait method instance + if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { + // Check that it implements the noop diagnostic + if cx.tcx.is_diagnostic_item(sym::ref_clone_method, i.def_id()) { + let span = expr.span; + + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + let message = "Call to noop method"; + lint.build(&message).emit() + }); + } + } + } + } + } + } + } +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 27bb45bcc8512..2207deb8fb5a0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -915,6 +915,7 @@ symbols! { receiver, recursion_limit, reexport_test_harness_main, + ref_clone_method, reference, reflect, reg, diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index a953a3a4182bc..12f0f9629a31f 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -104,6 +104,7 @@ /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] +#[rustc_diagnostic_item = "Clone"] pub trait Clone: Sized { /// Returns a copy of the value. /// @@ -221,6 +222,7 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for &T { #[inline] + #[rustc_diagnostic_item = "ref_clone_method"] fn clone(&self) -> Self { *self } From f49ed7a6b7aa3a44dd0444b508a1d0ddc09b0f15 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 5 Jan 2021 16:14:39 +0100 Subject: [PATCH 43/67] Add tests and support two more noop methods --- compiler/rustc_lint/src/noop_method_call.rs | 12 +++++- compiler/rustc_span/src/symbol.rs | 4 +- library/core/src/borrow.rs | 1 + library/core/src/clone.rs | 3 +- library/core/src/ops/deref.rs | 1 + src/test/ui/lint/noop-method-call.rs | 45 +++++++++++++++++++++ src/test/ui/lint/noop-method-call.stderr | 28 +++++++++++++ 7 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/lint/noop-method-call.rs create mode 100644 src/test/ui/lint/noop-method-call.stderr diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 098c50d5abe19..3ab3fab4272c7 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -54,11 +54,19 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // Resolve the trait method instance if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { // Check that it implements the noop diagnostic - if cx.tcx.is_diagnostic_item(sym::ref_clone_method, i.def_id()) { + tracing::debug!("Resolves to: {:?}", i.def_id()); + if [ + sym::noop_method_borrow, + sym::noop_method_clone, + sym::noop_method_deref, + ] + .iter() + .any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id())) + { let span = expr.span; cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let message = "Call to noop method"; + let message = "call to noop method"; lint.build(&message).emit() }); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2207deb8fb5a0..d39fbd61962e7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -789,6 +789,9 @@ symbols! { none_error, nontemporal_store, nontrapping_dash_fptoint: "nontrapping-fptoint", + noop_method_borrow, + noop_method_clone, + noop_method_deref, noreturn, nostack, not, @@ -915,7 +918,6 @@ symbols! { receiver, recursion_limit, reexport_test_harness_main, - ref_clone_method, reference, reflect, reg, diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index c9040cd0a1670..af2ad12dddf0a 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -219,6 +219,7 @@ impl BorrowMut for T { #[stable(feature = "rust1", since = "1.0.0")] impl Borrow for &T { + #[rustc_diagnostic_item = "noop_method_borrow"] fn borrow(&self) -> &T { &**self } diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 12f0f9629a31f..12b4feeb14ae3 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -104,7 +104,6 @@ /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] -#[rustc_diagnostic_item = "Clone"] pub trait Clone: Sized { /// Returns a copy of the value. /// @@ -222,7 +221,7 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for &T { #[inline] - #[rustc_diagnostic_item = "ref_clone_method"] + #[rustc_diagnostic_item = "noop_method_clone"] fn clone(&self) -> Self { *self } diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 2419771eae212..d503a30174191 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -78,6 +78,7 @@ pub trait Deref { impl Deref for &T { type Target = T; + #[rustc_diagnostic_item = "noop_method_deref"] fn deref(&self) -> &T { *self } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs new file mode 100644 index 0000000000000..4b81e04d3f7f9 --- /dev/null +++ b/src/test/ui/lint/noop-method-call.rs @@ -0,0 +1,45 @@ +// check-pass + +#![allow(unused)] + +use std::borrow::Borrow; +use std::ops::Deref; + +struct Foo(T); + +#[derive(Clone)] +struct Bar(T); + +struct DerefExample(T); + +impl Deref for DerefExample { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn main() { + let foo = &Foo(1u32); + let foo_clone: &Foo = foo.clone(); //~ WARNING call to noop method + + let bar = &Bar(1u32); + let bar_clone: Bar = bar.clone(); + + let deref = &&DerefExample(12u32); + let derefed: &DerefExample = deref.deref(); //~ WARNING call to noop method + + let deref = &DerefExample(12u32); + let derefed: &u32 = deref.deref(); + + let a = &&Foo(1u32); + let borrowed: &Foo = a.borrow(); //~ WARNING call to noop method +} + +fn generic(foo: &Foo) { + foo.clone(); +} + +fn non_generic(foo: &Foo) { + foo.clone(); //~ WARNING call to noop method +} diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr new file mode 100644 index 0000000000000..1120adee121b1 --- /dev/null +++ b/src/test/ui/lint/noop-method-call.stderr @@ -0,0 +1,28 @@ +warning: call to noop method + --> $DIR/noop-method-call.rs:24:32 + | +LL | let foo_clone: &Foo = foo.clone(); + | ^^^^^^^^^^^ + | + = note: `#[warn(noop_method_call)]` on by default + +warning: call to noop method + --> $DIR/noop-method-call.rs:30:39 + | +LL | let derefed: &DerefExample = deref.deref(); + | ^^^^^^^^^^^^^ + +warning: call to noop method + --> $DIR/noop-method-call.rs:36:31 + | +LL | let borrowed: &Foo = a.borrow(); + | ^^^^^^^^^^ + +warning: call to noop method + --> $DIR/noop-method-call.rs:44:5 + | +LL | foo.clone(); + | ^^^^^^^^^^^ + +warning: 4 warnings emitted + From a6d926d80db4a52398dea0cf29e6c501eab50170 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 5 Jan 2021 16:46:50 +0100 Subject: [PATCH 44/67] Fix tests --- compiler/rustc_codegen_ssa/src/back/rpath.rs | 2 +- compiler/rustc_lint/src/noop_method_call.rs | 9 ++++++++- compiler/rustc_middle/src/ty/error.rs | 2 -- compiler/rustc_mir/src/borrow_check/invalidation.rs | 8 ++++---- compiler/rustc_mir_build/src/build/matches/test.rs | 2 +- compiler/rustc_span/src/symbol.rs | 2 ++ .../src/traits/error_reporting/mod.rs | 2 +- compiler/rustc_traits/src/chalk/mod.rs | 2 +- compiler/rustc_typeck/src/check/callee.rs | 2 +- compiler/rustc_typeck/src/check/expr.rs | 2 +- library/core/src/borrow.rs | 1 + library/core/src/clone.rs | 1 + library/core/src/ops/deref.rs | 1 + src/test/ui/issues/issue-11820.rs | 10 ++++++---- src/test/ui/underscore-imports/cycle.rs | 1 + src/test/ui/underscore-imports/hygiene-2.rs | 1 + src/test/ui/underscore-imports/macro-expanded.rs | 1 + 17 files changed, 32 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 005d2efdd3b26..5f21046b05e47 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -24,7 +24,7 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec { debug!("preparing the RPATH!"); - let libs = config.used_crates.clone(); + let libs = config.used_crates; let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::>(); let rpaths = get_rpaths(config, &libs); let mut flags = rpaths_to_flags(&rpaths); diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 3ab3fab4272c7..dad557128f8b7 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -46,6 +46,14 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { { // Check that we're dealing with a trait method if let Some(trait_id) = cx.tcx.trait_of_item(did) { + // Check we're dealing with one of the traits we care about + if ![sym::Clone, sym::Deref, sym::Borrow] + .iter() + .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) + { + return; + } + let substs = cx.typeck_results().node_substs(expr.hir_id); // We can't resolve on types that recursively require monomorphization, // so check that we don't need to perfom substitution @@ -54,7 +62,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // Resolve the trait method instance if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { // Check that it implements the noop diagnostic - tracing::debug!("Resolves to: {:?}", i.def_id()); if [ sym::noop_method_borrow, sym::noop_method_clone, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index bf315c81588a9..f19cc99844926 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -12,7 +12,6 @@ use rustc_target::spec::abi; use std::borrow::Cow; use std::fmt; -use std::ops::Deref; #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)] pub struct ExpectedFound { @@ -548,7 +547,6 @@ impl Trait for X { TargetFeatureCast(def_id) => { let attrs = self.get_attrs(*def_id); let target_spans = attrs - .deref() .iter() .filter(|attr| attr.has_name(sym::target_feature)) .map(|attr| attr.span); diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs index 8c05e6fd5d0e4..e423e449746fc 100644 --- a/compiler/rustc_mir/src/borrow_check/invalidation.rs +++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs @@ -165,7 +165,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.consume_operand(location, value); // Invalidate all borrows of local places - let borrow_set = self.borrow_set.clone(); + let borrow_set = self.borrow_set; let resume = self.location_table.start_index(resume.start_location()); for (i, data) in borrow_set.iter_enumerated() { if borrow_of_local_data(data.borrowed_place) { @@ -177,7 +177,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => { // Invalidate all borrows of local places - let borrow_set = self.borrow_set.clone(); + let borrow_set = self.borrow_set; let start = self.location_table.start_index(location); for (i, data) in borrow_set.iter_enumerated() { if borrow_of_local_data(data.borrowed_place) { @@ -369,7 +369,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { ); let tcx = self.tcx; let body = self.body; - let borrow_set = self.borrow_set.clone(); + let borrow_set = self.borrow_set; let indices = self.borrow_set.indices(); each_borrow_involving_path( self, @@ -377,7 +377,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { body, location, (sd, place), - &borrow_set.clone(), + borrow_set, indices, |this, borrow_index, borrow| { match (rw, borrow.kind) { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 126fb957a6a99..4db7debee7e8f 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -51,7 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Constant { value } => Test { span: match_pair.pattern.span, - kind: TestKind::Eq { value, ty: match_pair.pattern.ty.clone() }, + kind: TestKind::Eq { value, ty: match_pair.pattern.ty }, }, PatKind::Range(range) => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d39fbd61962e7..61f9a080a5217 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -129,6 +129,7 @@ symbols! { BTreeMap, BTreeSet, BinaryHeap, + Borrow, C, CString, Center, @@ -141,6 +142,7 @@ symbols! { Decodable, Decoder, Default, + Deref, Encodable, Encoder, Eq, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index bfb5ebcea58b1..a3faf4cb7d4c1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -819,7 +819,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { sig.decl .inputs .iter() - .map(|arg| match arg.clone().kind { + .map(|arg| match arg.kind { hir::TyKind::Tup(ref tys) => ArgKind::Tuple( Some(arg.span), vec![("_".to_owned(), "_".to_owned()); tys.len()], diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index d98f18182c843..b7275bac19048 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -165,7 +165,7 @@ crate fn evaluate_goal<'tcx>( // let's just ignore that let sol = Canonical { max_universe: ty::UniverseIndex::from_usize(0), - variables: obligation.variables.clone(), + variables: obligation.variables, value: QueryResponse { var_values: CanonicalVarValues { var_values: IndexVec::new() } .make_identity(tcx), diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index ca1e79fac73e9..6ef63bcbbbf21 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -465,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected_arg_tys = self.expected_inputs_for_expected_output( call_expr.span, expected, - fn_sig.output().clone(), + fn_sig.output(), fn_sig.inputs(), ); diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 2faf128c491fd..48740e533da8e 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -711,7 +711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let ret_ty = ret_coercion.borrow().expected_ty(); - let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone()); + let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty); ret_coercion.borrow_mut().coerce( self, &self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)), diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index af2ad12dddf0a..a0cdf681f67e1 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -153,6 +153,7 @@ /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`String`]: ../../std/string/struct.String.html #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Borrow"] pub trait Borrow { /// Immutably borrows from an owned value. /// diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 12b4feeb14ae3..957769cdc5a62 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -104,6 +104,7 @@ /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "clone"] +#[rustc_diagnostic_item = "Clone"] pub trait Clone: Sized { /// Returns a copy of the value. /// diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index d503a30174191..10e3ce67448c8 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -60,6 +60,7 @@ #[doc(alias = "*")] #[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Deref"] pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/test/ui/issues/issue-11820.rs b/src/test/ui/issues/issue-11820.rs index 7ffe9652797cf..8a26624a05dc9 100644 --- a/src/test/ui/issues/issue-11820.rs +++ b/src/test/ui/issues/issue-11820.rs @@ -1,12 +1,14 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(noop_method_call)] + struct NoClone; fn main() { - let rnc = &NoClone; - let rsnc = &Some(NoClone); + let rnc = &NoClone; + let rsnc = &Some(NoClone); - let _: &NoClone = rnc.clone(); - let _: &Option = rsnc.clone(); + let _: &NoClone = rnc.clone(); + let _: &Option = rsnc.clone(); } diff --git a/src/test/ui/underscore-imports/cycle.rs b/src/test/ui/underscore-imports/cycle.rs index bacf9b2d5a96a..987410fa84b20 100644 --- a/src/test/ui/underscore-imports/cycle.rs +++ b/src/test/ui/underscore-imports/cycle.rs @@ -14,5 +14,6 @@ mod y { pub fn main() { use x::*; + #[allow(noop_method_call)] (&0).deref(); } diff --git a/src/test/ui/underscore-imports/hygiene-2.rs b/src/test/ui/underscore-imports/hygiene-2.rs index bea61eae6b51a..510d91d0d4624 100644 --- a/src/test/ui/underscore-imports/hygiene-2.rs +++ b/src/test/ui/underscore-imports/hygiene-2.rs @@ -29,5 +29,6 @@ m!(y); fn main() { use crate::y::*; + #[allow(noop_method_call)] (&()).deref(); } diff --git a/src/test/ui/underscore-imports/macro-expanded.rs b/src/test/ui/underscore-imports/macro-expanded.rs index 43f527bc9a408..55e86e848558d 100644 --- a/src/test/ui/underscore-imports/macro-expanded.rs +++ b/src/test/ui/underscore-imports/macro-expanded.rs @@ -3,6 +3,7 @@ // check-pass #![feature(decl_macro, rustc_attrs)] +#![allow(noop_method_call)] mod x { pub use std::ops::Not as _; From 618c395a8da1e284a2963b8da02450eb162e0478 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 6 Jan 2021 14:48:06 +0100 Subject: [PATCH 45/67] Bless test where order of error message changed --- src/test/ui/panic-handler/weak-lang-item.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr index 68e3e21df3e08..b7c040c7a850b 100644 --- a/src/test/ui/panic-handler/weak-lang-item.stderr +++ b/src/test/ui/panic-handler/weak-lang-item.stderr @@ -10,10 +10,10 @@ help: you can use `as` to change the binding name of the import LL | extern crate core as other_core; | -error: language item required, but not found: `eh_personality` - error: `#[panic_handler]` function required, but not found +error: language item required, but not found: `eh_personality` + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0259`. From 3a86184777e98935bef9b9662d090d6886c3c041 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 6 Jan 2021 17:56:34 +0100 Subject: [PATCH 46/67] Fix ui-full-deps suite --- library/alloc/src/collections/btree/map/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 4e48db7f49305..e636e490e1bf4 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1801,11 +1801,11 @@ fn test_occupied_entry_key() { let key = "hello there"; let value = "value goes here"; assert!(a.is_empty()); - a.insert(key.clone(), value.clone()); + a.insert(key, value); assert_eq!(a.len(), 1); assert_eq!(a[key], value); - match a.entry(key.clone()) { + match a.entry(key) { Vacant(_) => panic!(), Occupied(e) => assert_eq!(key, *e.key()), } @@ -1821,11 +1821,11 @@ fn test_vacant_entry_key() { let value = "value goes here"; assert!(a.is_empty()); - match a.entry(key.clone()) { + match a.entry(key) { Occupied(_) => panic!(), Vacant(e) => { assert_eq!(key, *e.key()); - e.insert(value.clone()); + e.insert(value); } } assert_eq!(a.len(), 1); From ee65416f0d50331b5fef4360ce36538028edebf9 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 6 Jan 2021 21:11:08 +0100 Subject: [PATCH 47/67] Fix core tests --- library/core/src/clone.rs | 1 + library/core/tests/clone.rs | 2 ++ library/core/tests/iter/adapters/intersperse.rs | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 957769cdc5a62..51a2dc03de318 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -111,6 +111,7 @@ pub trait Clone: Sized { /// # Examples /// /// ``` + /// # #![allow(noop_method_call)] /// let hello = "Hello"; // &str implements Clone /// /// assert_eq!("Hello", hello.clone()); diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs index c97a87aebce41..e5787d79c3226 100644 --- a/library/core/tests/clone.rs +++ b/library/core/tests/clone.rs @@ -1,3 +1,5 @@ +#![allow(noop_method_call)] + #[test] fn test_borrowed_clone() { let x = 5; diff --git a/library/core/tests/iter/adapters/intersperse.rs b/library/core/tests/iter/adapters/intersperse.rs index 9dbe232e4eec8..b336c03b5adbe 100644 --- a/library/core/tests/iter/adapters/intersperse.rs +++ b/library/core/tests/iter/adapters/intersperse.rs @@ -9,7 +9,7 @@ fn test_intersperse() { assert_eq!(v, vec![1]); let xs = ["a", "", "b", "c"]; - let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); + let v: Vec<&str> = xs.iter().map(|x| *x).intersperse(", ").collect(); let text: String = v.concat(); assert_eq!(text, "a, , b, c".to_string()); @@ -24,7 +24,7 @@ fn test_intersperse_size_hint() { assert_eq!(iter.size_hint(), (0, Some(0))); let xs = ["a", "", "b", "c"]; - let mut iter = xs.iter().map(|x| x.clone()).intersperse(", "); + let mut iter = xs.iter().map(|x| *x).intersperse(", "); assert_eq!(iter.size_hint(), (7, Some(7))); assert_eq!(iter.next(), Some("a")); From d3b49c2ed2c7bf35e6155ea25acbf657d8224eac Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 7 Jan 2021 11:24:32 +0100 Subject: [PATCH 48/67] Only allow new lint when not bootstrapping - since beta doesn't know about the lint --- library/core/tests/clone.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs index e5787d79c3226..2f2aa9a20f912 100644 --- a/library/core/tests/clone.rs +++ b/library/core/tests/clone.rs @@ -1,4 +1,4 @@ -#![allow(noop_method_call)] +#![cfg_attr(not(bootstrap), allow(noop_method_call))] #[test] fn test_borrowed_clone() { From c5ff54cbdb6b0da742110b416cdbcf0ca0ff0fc4 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Thu, 7 Jan 2021 13:13:25 +0100 Subject: [PATCH 49/67] Fix std tests --- library/std/src/collections/hash/map/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 467968354e25d..819be14222752 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -774,11 +774,11 @@ fn test_occupied_entry_key() { let key = "hello there"; let value = "value goes here"; assert!(a.is_empty()); - a.insert(key.clone(), value.clone()); + a.insert(key, value); assert_eq!(a.len(), 1); assert_eq!(a[key], value); - match a.entry(key.clone()) { + match a.entry(key) { Vacant(_) => panic!(), Occupied(e) => assert_eq!(key, *e.key()), } @@ -793,11 +793,11 @@ fn test_vacant_entry_key() { let value = "value goes here"; assert!(a.is_empty()); - match a.entry(key.clone()) { + match a.entry(key) { Occupied(_) => panic!(), Vacant(e) => { assert_eq!(key, *e.key()); - e.insert(value.clone()); + e.insert(value); } } assert_eq!(a.len(), 1); From 217c88655b1155796739edbf415e7ce37d30830b Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Fri, 8 Jan 2021 11:37:52 +0100 Subject: [PATCH 50/67] Improve warning --- compiler/rustc_lint/src/noop_method_call.rs | 10 ++++++---- src/test/ui/lint/noop-method-call.rs | 8 ++++---- src/test/ui/lint/noop-method-call.stderr | 16 ++++++++-------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index dad557128f8b7..b9b5009d9dd95 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -70,11 +70,13 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { .iter() .any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id())) { - let span = expr.span; + let expr_span = expr.span; - cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let message = "call to noop method"; - lint.build(&message).emit() + cx.struct_span_lint(NOOP_METHOD_CALL, expr_span, |lint| { + let message = "call to method that does nothing"; + lint.build(&message) + .span_label(expr_span, "unnecessary method call") + .emit() }); } } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index 4b81e04d3f7f9..b8ff75845bd7d 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -21,19 +21,19 @@ impl Deref for DerefExample { fn main() { let foo = &Foo(1u32); - let foo_clone: &Foo = foo.clone(); //~ WARNING call to noop method + let foo_clone: &Foo = foo.clone(); //~ WARNING call to method that does nothing [noop_method_call] let bar = &Bar(1u32); let bar_clone: Bar = bar.clone(); let deref = &&DerefExample(12u32); - let derefed: &DerefExample = deref.deref(); //~ WARNING call to noop method + let derefed: &DerefExample = deref.deref(); //~ WARNING call to method that does nothing [noop_method_call] let deref = &DerefExample(12u32); let derefed: &u32 = deref.deref(); let a = &&Foo(1u32); - let borrowed: &Foo = a.borrow(); //~ WARNING call to noop method + let borrowed: &Foo = a.borrow(); //~ WARNING call to method that does nothing [noop_method_call] } fn generic(foo: &Foo) { @@ -41,5 +41,5 @@ fn generic(foo: &Foo) { } fn non_generic(foo: &Foo) { - foo.clone(); //~ WARNING call to noop method + foo.clone(); //~ WARNING call to method that does nothing [noop_method_call] } diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index 1120adee121b1..f5b766f42333f 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -1,28 +1,28 @@ -warning: call to noop method +warning: call to method that does nothing --> $DIR/noop-method-call.rs:24:32 | LL | let foo_clone: &Foo = foo.clone(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default -warning: call to noop method +warning: call to method that does nothing --> $DIR/noop-method-call.rs:30:39 | LL | let derefed: &DerefExample = deref.deref(); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ unnecessary method call -warning: call to noop method +warning: call to method that does nothing --> $DIR/noop-method-call.rs:36:31 | LL | let borrowed: &Foo = a.borrow(); - | ^^^^^^^^^^ + | ^^^^^^^^^^ unnecessary method call -warning: call to noop method +warning: call to method that does nothing --> $DIR/noop-method-call.rs:44:5 | LL | foo.clone(); - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ unnecessary method call warning: 4 warnings emitted From 16c4afbde4bcc0b2471cd48cf29378d557a8f4ab Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Fri, 8 Jan 2021 12:09:29 +0100 Subject: [PATCH 51/67] Fix tidy errors --- src/test/ui/lint/noop-method-call.rs | 9 ++++++--- src/test/ui/lint/noop-method-call.stderr | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index b8ff75845bd7d..9f0ab3960f8dd 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -21,19 +21,22 @@ impl Deref for DerefExample { fn main() { let foo = &Foo(1u32); - let foo_clone: &Foo = foo.clone(); //~ WARNING call to method that does nothing [noop_method_call] + let foo_clone: &Foo = foo.clone(); + //~^ WARNING call to method that does nothing [noop_method_call] let bar = &Bar(1u32); let bar_clone: Bar = bar.clone(); let deref = &&DerefExample(12u32); - let derefed: &DerefExample = deref.deref(); //~ WARNING call to method that does nothing [noop_method_call] + let derefed: &DerefExample = deref.deref(); + //~^ WARNING call to method that does nothing [noop_method_call] let deref = &DerefExample(12u32); let derefed: &u32 = deref.deref(); let a = &&Foo(1u32); - let borrowed: &Foo = a.borrow(); //~ WARNING call to method that does nothing [noop_method_call] + let borrowed: &Foo = a.borrow(); + //~^ WARNING call to method that does nothing [noop_method_call] } fn generic(foo: &Foo) { diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index f5b766f42333f..32acf1632336d 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -7,19 +7,19 @@ LL | let foo_clone: &Foo = foo.clone(); = note: `#[warn(noop_method_call)]` on by default warning: call to method that does nothing - --> $DIR/noop-method-call.rs:30:39 + --> $DIR/noop-method-call.rs:31:39 | LL | let derefed: &DerefExample = deref.deref(); | ^^^^^^^^^^^^^ unnecessary method call warning: call to method that does nothing - --> $DIR/noop-method-call.rs:36:31 + --> $DIR/noop-method-call.rs:38:31 | LL | let borrowed: &Foo = a.borrow(); | ^^^^^^^^^^ unnecessary method call warning: call to method that does nothing - --> $DIR/noop-method-call.rs:44:5 + --> $DIR/noop-method-call.rs:47:5 | LL | foo.clone(); | ^^^^^^^^^^^ unnecessary method call From 95e330bd0197a658096dfa1922ec3b3e6a4e6b78 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Mon, 11 Jan 2021 11:47:16 +0100 Subject: [PATCH 52/67] Update error message --- compiler/rustc_lint/src/noop_method_call.rs | 9 ++++++--- src/test/ui/issues/issue-11820.rs | 8 ++++---- src/test/ui/lint/noop-method-call.rs | 9 +++++---- src/test/ui/lint/noop-method-call.stderr | 19 +++++++++++++++---- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index b9b5009d9dd95..e91dd37d8aaae 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -39,7 +39,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // We only care about method calls - if let ExprKind::MethodCall(..) = expr.kind { + if let ExprKind::MethodCall(call, ..) = expr.kind { // Get the `DefId` only when dealing with an `AssocFn` if let Some((DefKind::AssocFn, did)) = cx.typeck_results().type_dependent_def(expr.hir_id) @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { } let substs = cx.typeck_results().node_substs(expr.hir_id); - // We can't resolve on types that recursively require monomorphization, + // We can't resolve on types that require monomorphization, // so check that we don't need to perfom substitution if !substs.needs_subst() { let param_env = cx.tcx.param_env(trait_id); @@ -73,9 +73,12 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { let expr_span = expr.span; cx.struct_span_lint(NOOP_METHOD_CALL, expr_span, |lint| { - let message = "call to method that does nothing"; + let method = &call.ident.name; + let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); lint.build(&message) .span_label(expr_span, "unnecessary method call") + .note("the type the method is being called on and the return type are functionally equivalent.") + .note("therefore, the method call doesn't actually do anything and can be removed.") .emit() }); } diff --git a/src/test/ui/issues/issue-11820.rs b/src/test/ui/issues/issue-11820.rs index 8a26624a05dc9..dc6349b10ee58 100644 --- a/src/test/ui/issues/issue-11820.rs +++ b/src/test/ui/issues/issue-11820.rs @@ -6,9 +6,9 @@ struct NoClone; fn main() { - let rnc = &NoClone; - let rsnc = &Some(NoClone); + let rnc = &NoClone; + let rsnc = &Some(NoClone); - let _: &NoClone = rnc.clone(); - let _: &Option = rsnc.clone(); + let _: &NoClone = rnc.clone(); + let _: &Option = rsnc.clone(); } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index 9f0ab3960f8dd..b8aa55e1e1da6 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -22,21 +22,21 @@ impl Deref for DerefExample { fn main() { let foo = &Foo(1u32); let foo_clone: &Foo = foo.clone(); - //~^ WARNING call to method that does nothing [noop_method_call] + //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call] let bar = &Bar(1u32); let bar_clone: Bar = bar.clone(); let deref = &&DerefExample(12u32); let derefed: &DerefExample = deref.deref(); - //~^ WARNING call to method that does nothing [noop_method_call] + //~^ WARNING call to `.deref()` on a reference in this situation does nothing [noop_method_call] let deref = &DerefExample(12u32); let derefed: &u32 = deref.deref(); let a = &&Foo(1u32); let borrowed: &Foo = a.borrow(); - //~^ WARNING call to method that does nothing [noop_method_call] + //~^ WARNING call to `.borrow()` on a reference in this situation does nothing [noop_method_call] } fn generic(foo: &Foo) { @@ -44,5 +44,6 @@ fn generic(foo: &Foo) { } fn non_generic(foo: &Foo) { - foo.clone(); //~ WARNING call to method that does nothing [noop_method_call] + foo.clone(); + //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call] } diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index 32acf1632336d..f9cc9735d54f6 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -1,28 +1,39 @@ -warning: call to method that does nothing +warning: call to `.clone()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:24:32 | LL | let foo_clone: &Foo = foo.clone(); | ^^^^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default + = note: the type the method is being called on and the return type are functionally equivalent. + = note: therefore, the method call doesn't actually do anything and can be removed. -warning: call to method that does nothing +warning: call to `.deref()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:31:39 | LL | let derefed: &DerefExample = deref.deref(); | ^^^^^^^^^^^^^ unnecessary method call + | + = note: the type the method is being called on and the return type are functionally equivalent. + = note: therefore, the method call doesn't actually do anything and can be removed. -warning: call to method that does nothing +warning: call to `.borrow()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:38:31 | LL | let borrowed: &Foo = a.borrow(); | ^^^^^^^^^^ unnecessary method call + | + = note: the type the method is being called on and the return type are functionally equivalent. + = note: therefore, the method call doesn't actually do anything and can be removed. -warning: call to method that does nothing +warning: call to `.clone()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:47:5 | LL | foo.clone(); | ^^^^^^^^^^^ unnecessary method call + | + = note: the type the method is being called on and the return type are functionally equivalent. + = note: therefore, the method call doesn't actually do anything and can be removed. warning: 4 warnings emitted From 316e9db0cf86852b0150d8f0d475ba9a1dcc4774 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Mon, 11 Jan 2021 19:02:19 +0100 Subject: [PATCH 53/67] Fix tidy error --- src/test/ui/lint/noop-method-call.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index b8aa55e1e1da6..bc61d619abe82 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -22,21 +22,21 @@ impl Deref for DerefExample { fn main() { let foo = &Foo(1u32); let foo_clone: &Foo = foo.clone(); - //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call] + //~^ WARNING call to `.clone()` on a reference in this situation does nothing let bar = &Bar(1u32); let bar_clone: Bar = bar.clone(); let deref = &&DerefExample(12u32); let derefed: &DerefExample = deref.deref(); - //~^ WARNING call to `.deref()` on a reference in this situation does nothing [noop_method_call] + //~^ WARNING call to `.deref()` on a reference in this situation does nothing let deref = &DerefExample(12u32); let derefed: &u32 = deref.deref(); let a = &&Foo(1u32); let borrowed: &Foo = a.borrow(); - //~^ WARNING call to `.borrow()` on a reference in this situation does nothing [noop_method_call] + //~^ WARNING call to `.borrow()` on a reference in this situation does nothing } fn generic(foo: &Foo) { @@ -45,5 +45,5 @@ fn generic(foo: &Foo) { fn non_generic(foo: &Foo) { foo.clone(); - //~^ WARNING call to `.clone()` on a reference in this situation does nothing [noop_method_call] + //~^ WARNING call to `.clone()` on a reference in this situation does nothing } From 49f32e0c8e78948210654299a8c19b2e0f0cbfa9 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 12 Jan 2021 14:58:51 +0100 Subject: [PATCH 54/67] Improve error messages --- compiler/rustc_lint/src/noop_method_call.rs | 18 +++++++++---- src/test/ui/lint/noop-method-call.stderr | 28 +++++++++------------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index e91dd37d8aaae..1aa4a986cd1fe 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -39,7 +39,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // We only care about method calls - if let ExprKind::MethodCall(call, ..) = expr.kind { + if let ExprKind::MethodCall(call, _, elements, _) = expr.kind { // Get the `DefId` only when dealing with an `AssocFn` if let Some((DefKind::AssocFn, did)) = cx.typeck_results().type_dependent_def(expr.hir_id) @@ -70,15 +70,23 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { .iter() .any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id())) { + let method = &call.ident.name; + let receiver = &elements[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver); let expr_span = expr.span; + let note = format!( + "the type `{:?}` which `{}` is being called on is the same as the type returned from `{}`, \ + so the method call does not do anything and can be removed.", + receiver_ty, method, method + ); - cx.struct_span_lint(NOOP_METHOD_CALL, expr_span, |lint| { + let span = expr_span.with_lo(receiver.span.hi()); + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { let method = &call.ident.name; let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); lint.build(&message) - .span_label(expr_span, "unnecessary method call") - .note("the type the method is being called on and the return type are functionally equivalent.") - .note("therefore, the method call doesn't actually do anything and can be removed.") + .span_label(span, "unnecessary method call") + .note(¬e) .emit() }); } diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index f9cc9735d54f6..7e27bf3abf9f3 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -1,39 +1,35 @@ warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:24:32 + --> $DIR/noop-method-call.rs:24:35 | LL | let foo_clone: &Foo = foo.clone(); - | ^^^^^^^^^^^ unnecessary method call + | ^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default - = note: the type the method is being called on and the return type are functionally equivalent. - = note: therefore, the method call doesn't actually do anything and can be removed. + = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. warning: call to `.deref()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:31:39 + --> $DIR/noop-method-call.rs:31:44 | LL | let derefed: &DerefExample = deref.deref(); - | ^^^^^^^^^^^^^ unnecessary method call + | ^^^^^^^^ unnecessary method call | - = note: the type the method is being called on and the return type are functionally equivalent. - = note: therefore, the method call doesn't actually do anything and can be removed. + = note: the type `&&DerefExample` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed. warning: call to `.borrow()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:38:31 + --> $DIR/noop-method-call.rs:38:32 | LL | let borrowed: &Foo = a.borrow(); - | ^^^^^^^^^^ unnecessary method call + | ^^^^^^^^^ unnecessary method call | - = note: the type the method is being called on and the return type are functionally equivalent. - = note: therefore, the method call doesn't actually do anything and can be removed. + = note: the type `&&Foo` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed. warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:47:5 + --> $DIR/noop-method-call.rs:47:8 | LL | foo.clone(); - | ^^^^^^^^^^^ unnecessary method call + | ^^^^^^^^ unnecessary method call | - = note: the type the method is being called on and the return type are functionally equivalent. - = note: therefore, the method call doesn't actually do anything and can be removed. + = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. warning: 4 warnings emitted From e48670c34a3f5ab3fe9defcc61861999f3f14e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 Jan 2021 18:37:32 -0800 Subject: [PATCH 55/67] Increase accuracy of lint trigger --- compiler/rustc_lint/src/noop_method_call.rs | 58 +++++++++++++-------- src/test/ui/lint/noop-method-call.rs | 3 ++ src/test/ui/lint/noop-method-call.stderr | 10 ++-- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 1aa4a986cd1fe..04d87dc959273 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -62,33 +62,45 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // Resolve the trait method instance if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { // Check that it implements the noop diagnostic - if [ - sym::noop_method_borrow, - sym::noop_method_clone, - sym::noop_method_deref, + for (s, peel_ref) in [ + (sym::noop_method_borrow, true), + (sym::noop_method_clone, false), + (sym::noop_method_deref, true), ] .iter() - .any(|s| cx.tcx.is_diagnostic_item(*s, i.def_id())) { - let method = &call.ident.name; - let receiver = &elements[0]; - let receiver_ty = cx.typeck_results().expr_ty(receiver); - let expr_span = expr.span; - let note = format!( - "the type `{:?}` which `{}` is being called on is the same as the type returned from `{}`, \ - so the method call does not do anything and can be removed.", - receiver_ty, method, method - ); - - let span = expr_span.with_lo(receiver.span.hi()); - cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + if cx.tcx.is_diagnostic_item(*s, i.def_id()) { let method = &call.ident.name; - let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); - lint.build(&message) - .span_label(span, "unnecessary method call") - .note(¬e) - .emit() - }); + let receiver = &elements[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver); + let receiver_ty = match receiver_ty.kind() { + // Remove one borrow from the receiver as all the trait methods + // we care about here have a `&self` receiver. + ty::Ref(_, ty, _) if *peel_ref => ty, + _ => receiver_ty, + }; + let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); + if receiver_ty != expr_ty { + return; + } + let expr_span = expr.span; + let note = format!( + "the type `{:?}` which `{}` is being called on is the same as \ + the type returned from `{}`, so the method call does not do \ + anything and can be removed", + receiver_ty, method, method, + ); + + let span = expr_span.with_lo(receiver.span.hi()); + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + let method = &call.ident.name; + let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); + lint.build(&message) + .span_label(span, "unnecessary method call") + .note(¬e) + .emit() + }); + } } } } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index bc61d619abe82..70363a191e9e9 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -37,6 +37,9 @@ fn main() { let a = &&Foo(1u32); let borrowed: &Foo = a.borrow(); //~^ WARNING call to `.borrow()` on a reference in this situation does nothing + + let xs = ["a", "b", "c"]; + let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead } fn generic(foo: &Foo) { diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index 7e27bf3abf9f3..316c47975e6de 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -5,7 +5,7 @@ LL | let foo_clone: &Foo = foo.clone(); | ^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default - = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. + = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed warning: call to `.deref()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:31:44 @@ -13,7 +13,7 @@ warning: call to `.deref()` on a reference in this situation does nothing LL | let derefed: &DerefExample = deref.deref(); | ^^^^^^^^ unnecessary method call | - = note: the type `&&DerefExample` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed. + = note: the type `&DerefExample` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed warning: call to `.borrow()` on a reference in this situation does nothing --> $DIR/noop-method-call.rs:38:32 @@ -21,15 +21,15 @@ warning: call to `.borrow()` on a reference in this situation does nothing LL | let borrowed: &Foo = a.borrow(); | ^^^^^^^^^ unnecessary method call | - = note: the type `&&Foo` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed. + = note: the type `&Foo` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:47:8 + --> $DIR/noop-method-call.rs:50:8 | LL | foo.clone(); | ^^^^^^^^ unnecessary method call | - = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed. + = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed warning: 4 warnings emitted From 055db16479937d0a567b2318c775a25ab6cb7d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Jan 2021 10:39:25 -0800 Subject: [PATCH 56/67] Clean up code rightward drift --- compiler/rustc_lint/src/noop_method_call.rs | 144 +++++++++++--------- 1 file changed, 79 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 04d87dc959273..b4ee1f9157c82 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -38,73 +38,87 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // We only care about method calls - if let ExprKind::MethodCall(call, _, elements, _) = expr.kind { - // Get the `DefId` only when dealing with an `AssocFn` - if let Some((DefKind::AssocFn, did)) = - cx.typeck_results().type_dependent_def(expr.hir_id) - { - // Check that we're dealing with a trait method - if let Some(trait_id) = cx.tcx.trait_of_item(did) { - // Check we're dealing with one of the traits we care about - if ![sym::Clone, sym::Deref, sym::Borrow] + // We only care about method calls. + let (call, elements) = match expr.kind { + ExprKind::MethodCall(call, _, elements, _) => (call, elements), + _ => return, + }; + // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow` + // traits and ignore any other method call. + let (trait_id, did) = match cx.typeck_results().type_dependent_def(expr.hir_id) { + // Verify we are dealing with a method/associated function. + Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) { + // Check that we're dealing with a trait method for one of the traits we care about. + Some(trait_id) + if [sym::Clone, sym::Deref, sym::Borrow] .iter() - .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) - { - return; - } - - let substs = cx.typeck_results().node_substs(expr.hir_id); - // We can't resolve on types that require monomorphization, - // so check that we don't need to perfom substitution - if !substs.needs_subst() { - let param_env = cx.tcx.param_env(trait_id); - // Resolve the trait method instance - if let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, param_env, did, substs) { - // Check that it implements the noop diagnostic - for (s, peel_ref) in [ - (sym::noop_method_borrow, true), - (sym::noop_method_clone, false), - (sym::noop_method_deref, true), - ] - .iter() - { - if cx.tcx.is_diagnostic_item(*s, i.def_id()) { - let method = &call.ident.name; - let receiver = &elements[0]; - let receiver_ty = cx.typeck_results().expr_ty(receiver); - let receiver_ty = match receiver_ty.kind() { - // Remove one borrow from the receiver as all the trait methods - // we care about here have a `&self` receiver. - ty::Ref(_, ty, _) if *peel_ref => ty, - _ => receiver_ty, - }; - let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); - if receiver_ty != expr_ty { - return; - } - let expr_span = expr.span; - let note = format!( - "the type `{:?}` which `{}` is being called on is the same as \ - the type returned from `{}`, so the method call does not do \ - anything and can be removed", - receiver_ty, method, method, - ); - - let span = expr_span.with_lo(receiver.span.hi()); - cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { - let method = &call.ident.name; - let message = format!("call to `.{}()` on a reference in this situation does nothing", &method); - lint.build(&message) - .span_label(span, "unnecessary method call") - .note(¬e) - .emit() - }); - } - } - } - } + .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => + { + (trait_id, did) } + _ => return, + }, + _ => return, + }; + let substs = cx.typeck_results().node_substs(expr.hir_id); + if substs.needs_subst() { + // We can't resolve on types that require monomorphization, so we don't handle them if + // we need to perfom substitution. + return; + } + let param_env = cx.tcx.param_env(trait_id); + // Resolve the trait method instance. + let i = match ty::Instance::resolve(cx.tcx, param_env, did, substs) { + Ok(Some(i)) => i, + _ => return, + }; + // (Re)check that it implements the noop diagnostic. + for (s, peel_ref) in [ + (sym::noop_method_borrow, true), + (sym::noop_method_clone, false), + (sym::noop_method_deref, true), + ] + .iter() + { + if cx.tcx.is_diagnostic_item(*s, i.def_id()) { + let method = &call.ident.name; + let receiver = &elements[0]; + let receiver_ty = cx.typeck_results().expr_ty(receiver); + let receiver_ty = match receiver_ty.kind() { + // Remove one borrow from the receiver if appropriate to positively verify that + // the receiver `&self` type and the return type are the same, depending on the + // involved trait being checked. + ty::Ref(_, ty, _) if *peel_ref => ty, + // When it comes to `Clone` we need to check the `receiver_ty` directly. + // FIXME: we must come up with a better strategy for this. + _ => receiver_ty, + }; + let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); + if receiver_ty != expr_ty { + // This lint will only trigger if the receiver type and resulting expression \ + // type are the same, implying that the method call is unnecessary. + return; + } + let expr_span = expr.span; + let note = format!( + "the type `{:?}` which `{}` is being called on is the same as \ + the type returned from `{}`, so the method call does not do \ + anything and can be removed", + receiver_ty, method, method, + ); + + let span = expr_span.with_lo(receiver.span.hi()); + cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| { + let method = &call.ident.name; + let message = format!( + "call to `.{}()` on a reference in this situation does nothing", + &method, + ); + lint.build(&message) + .span_label(span, "unnecessary method call") + .note(¬e) + .emit() + }); } } } From 4be7052b1a81f8f39d9ad23781e19f30d071f572 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Mon, 18 Jan 2021 14:15:19 +0100 Subject: [PATCH 57/67] Allow noop_method_call in clippy ui test --- src/tools/clippy/tests/ui/unnecessary_clone.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.rs b/src/tools/clippy/tests/ui/unnecessary_clone.rs index 6770a7fac90fd..ce26634a995d9 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.rs +++ b/src/tools/clippy/tests/ui/unnecessary_clone.rs @@ -1,7 +1,7 @@ // does not test any rustfixable lints #![warn(clippy::clone_on_ref_ptr)] -#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wraps)] +#![allow(unused, noop_method_call, clippy::redundant_clone, clippy::unnecessary_wraps)] use std::cell::RefCell; use std::rc::{self, Rc}; From 6bf6652616ca75dde30cbdd021942433ae519730 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 10 Feb 2021 11:08:00 +0100 Subject: [PATCH 58/67] Move unrelated ui test back to what it was before --- src/test/ui/panic-handler/weak-lang-item.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/panic-handler/weak-lang-item.stderr b/src/test/ui/panic-handler/weak-lang-item.stderr index b7c040c7a850b..68e3e21df3e08 100644 --- a/src/test/ui/panic-handler/weak-lang-item.stderr +++ b/src/test/ui/panic-handler/weak-lang-item.stderr @@ -10,10 +10,10 @@ help: you can use `as` to change the binding name of the import LL | extern crate core as other_core; | -error: `#[panic_handler]` function required, but not found - error: language item required, but not found: `eh_personality` +error: `#[panic_handler]` function required, but not found + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0259`. From da3995f0ec3085de42dcce9e91dbb5662b2c99d3 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 16 Feb 2021 15:12:19 +0100 Subject: [PATCH 59/67] Remove lint pass on borrow and deref --- compiler/rustc_lint/src/noop_method_call.rs | 12 +----- compiler/rustc_span/src/symbol.rs | 3 -- library/core/src/borrow.rs | 2 - library/core/src/ops/deref.rs | 2 - src/test/ui/lint/noop-method-call.rs | 46 +++++++-------------- src/test/ui/lint/noop-method-call.stderr | 34 ++++----------- 6 files changed, 25 insertions(+), 74 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index b4ee1f9157c82..335c3c575e766 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -50,9 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) { // Check that we're dealing with a trait method for one of the traits we care about. Some(trait_id) - if [sym::Clone, sym::Deref, sym::Borrow] - .iter() - .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => + if [sym::Clone].iter().any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => { (trait_id, did) } @@ -73,13 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { _ => return, }; // (Re)check that it implements the noop diagnostic. - for (s, peel_ref) in [ - (sym::noop_method_borrow, true), - (sym::noop_method_clone, false), - (sym::noop_method_deref, true), - ] - .iter() - { + for (s, peel_ref) in [(sym::noop_method_clone, false)].iter() { if cx.tcx.is_diagnostic_item(*s, i.def_id()) { let method = &call.ident.name; let receiver = &elements[0]; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 61f9a080a5217..f43b180e06321 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -142,7 +142,6 @@ symbols! { Decodable, Decoder, Default, - Deref, Encodable, Encoder, Eq, @@ -791,9 +790,7 @@ symbols! { none_error, nontemporal_store, nontrapping_dash_fptoint: "nontrapping-fptoint", - noop_method_borrow, noop_method_clone, - noop_method_deref, noreturn, nostack, not, diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index a0cdf681f67e1..c9040cd0a1670 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -153,7 +153,6 @@ /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`String`]: ../../std/string/struct.String.html #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "Borrow"] pub trait Borrow { /// Immutably borrows from an owned value. /// @@ -220,7 +219,6 @@ impl BorrowMut for T { #[stable(feature = "rust1", since = "1.0.0")] impl Borrow for &T { - #[rustc_diagnostic_item = "noop_method_borrow"] fn borrow(&self) -> &T { &**self } diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 10e3ce67448c8..2419771eae212 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -60,7 +60,6 @@ #[doc(alias = "*")] #[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "Deref"] pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -79,7 +78,6 @@ pub trait Deref { impl Deref for &T { type Target = T; - #[rustc_diagnostic_item = "noop_method_deref"] fn deref(&self) -> &T { *self } diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index 70363a191e9e9..8e4b5bf4d12c7 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -2,51 +2,33 @@ #![allow(unused)] -use std::borrow::Borrow; -use std::ops::Deref; - -struct Foo(T); +struct NonCloneType(T); #[derive(Clone)] -struct Bar(T); - -struct DerefExample(T); - -impl Deref for DerefExample { - type Target = T; - fn deref(&self) -> &Self::Target { - &self.0 - } -} +struct CloneType(T); fn main() { - let foo = &Foo(1u32); - let foo_clone: &Foo = foo.clone(); + let non_clone_type_ref = &NonCloneType(1u32); + let non_clone_type_ref_clone: &NonCloneType = non_clone_type_ref.clone(); //~^ WARNING call to `.clone()` on a reference in this situation does nothing - let bar = &Bar(1u32); - let bar_clone: Bar = bar.clone(); - - let deref = &&DerefExample(12u32); - let derefed: &DerefExample = deref.deref(); - //~^ WARNING call to `.deref()` on a reference in this situation does nothing - - let deref = &DerefExample(12u32); - let derefed: &u32 = deref.deref(); + let clone_type_ref = &CloneType(1u32); + let clone_type_ref_clone: CloneType = clone_type_ref.clone(); - let a = &&Foo(1u32); - let borrowed: &Foo = a.borrow(); - //~^ WARNING call to `.borrow()` on a reference in this situation does nothing + // Calling clone on a double reference doesn't warn since the method call itself + // peels the outer reference off + let clone_type_ref = &&CloneType(1u32); + let clone_type_ref_clone: &CloneType = clone_type_ref.clone(); let xs = ["a", "b", "c"]; let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead } -fn generic(foo: &Foo) { - foo.clone(); +fn generic(non_clone_type: &NonCloneType) { + non_clone_type.clone(); } -fn non_generic(foo: &Foo) { - foo.clone(); +fn non_generic(non_clone_type: &NonCloneType) { + non_clone_type.clone(); //~^ WARNING call to `.clone()` on a reference in this situation does nothing } diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index 316c47975e6de..85a67f538407c 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -1,35 +1,19 @@ warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:24:35 + --> $DIR/noop-method-call.rs:12:74 | -LL | let foo_clone: &Foo = foo.clone(); - | ^^^^^^^^ unnecessary method call +LL | let non_clone_type_ref_clone: &NonCloneType = non_clone_type_ref.clone(); + | ^^^^^^^^ unnecessary method call | = note: `#[warn(noop_method_call)]` on by default - = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed - -warning: call to `.deref()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:31:44 - | -LL | let derefed: &DerefExample = deref.deref(); - | ^^^^^^^^ unnecessary method call - | - = note: the type `&DerefExample` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed - -warning: call to `.borrow()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:38:32 - | -LL | let borrowed: &Foo = a.borrow(); - | ^^^^^^^^^ unnecessary method call - | - = note: the type `&Foo` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed + = note: the type `&NonCloneType` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:50:8 + --> $DIR/noop-method-call.rs:32:19 | -LL | foo.clone(); - | ^^^^^^^^ unnecessary method call +LL | non_clone_type.clone(); + | ^^^^^^^^ unnecessary method call | - = note: the type `&Foo` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed + = note: the type `&NonCloneType` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed -warning: 4 warnings emitted +warning: 2 warnings emitted From 1999a3147f5ab65cd556d45e631be5c18fbaebf4 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Tue, 16 Feb 2021 22:39:05 +0100 Subject: [PATCH 60/67] Fix borrow and deref --- compiler/rustc_lint/src/noop_method_call.rs | 18 ++++------ compiler/rustc_span/src/symbol.rs | 3 ++ library/core/src/borrow.rs | 2 ++ library/core/src/ops/deref.rs | 2 ++ library/core/tests/clone.rs | 2 -- src/test/ui/issues/issue-11820.rs | 2 -- src/test/ui/lint/noop-method-call.rs | 30 +++++++++++++--- src/test/ui/lint/noop-method-call.stderr | 36 ++++++++++++++----- src/test/ui/underscore-imports/cycle.rs | 1 - .../ui/underscore-imports/macro-expanded.rs | 1 - .../clippy/tests/ui/unnecessary_clone.rs | 2 +- 11 files changed, 67 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 335c3c575e766..3a1b9c85fd1bd 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -15,6 +15,7 @@ declare_lint! { /// /// ```rust /// # #![allow(unused)] + /// #![deny(noop_method_call)] /// struct Foo; /// let foo = &Foo; /// let clone: &Foo = foo.clone(); @@ -30,7 +31,7 @@ declare_lint! { /// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything /// as references are copy. This lint detects these calls and warns the user about them. pub NOOP_METHOD_CALL, - Warn, + Allow, "detects the use of well-known noop methods" } @@ -50,7 +51,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) { // Check that we're dealing with a trait method for one of the traits we care about. Some(trait_id) - if [sym::Clone].iter().any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => + if [sym::Clone, sym::Deref, sym::Borrow] + .iter() + .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => { (trait_id, did) } @@ -71,20 +74,11 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { _ => return, }; // (Re)check that it implements the noop diagnostic. - for (s, peel_ref) in [(sym::noop_method_clone, false)].iter() { + for s in [sym::noop_method_clone, sym::noop_method_deref, sym::noop_method_borrow].iter() { if cx.tcx.is_diagnostic_item(*s, i.def_id()) { let method = &call.ident.name; let receiver = &elements[0]; let receiver_ty = cx.typeck_results().expr_ty(receiver); - let receiver_ty = match receiver_ty.kind() { - // Remove one borrow from the receiver if appropriate to positively verify that - // the receiver `&self` type and the return type are the same, depending on the - // involved trait being checked. - ty::Ref(_, ty, _) if *peel_ref => ty, - // When it comes to `Clone` we need to check the `receiver_ty` directly. - // FIXME: we must come up with a better strategy for this. - _ => receiver_ty, - }; let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); if receiver_ty != expr_ty { // This lint will only trigger if the receiver type and resulting expression \ diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f43b180e06321..61f9a080a5217 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -142,6 +142,7 @@ symbols! { Decodable, Decoder, Default, + Deref, Encodable, Encoder, Eq, @@ -790,7 +791,9 @@ symbols! { none_error, nontemporal_store, nontrapping_dash_fptoint: "nontrapping-fptoint", + noop_method_borrow, noop_method_clone, + noop_method_deref, noreturn, nostack, not, diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index c9040cd0a1670..f28be20aaa1e6 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -153,6 +153,7 @@ /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`String`]: ../../std/string/struct.String.html #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Borrow"] pub trait Borrow { /// Immutably borrows from an owned value. /// @@ -205,6 +206,7 @@ pub trait BorrowMut: Borrow { #[stable(feature = "rust1", since = "1.0.0")] impl Borrow for T { + #[rustc_diagnostic_item = "noop_method_borrow"] fn borrow(&self) -> &T { self } diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 2419771eae212..10e3ce67448c8 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -60,6 +60,7 @@ #[doc(alias = "*")] #[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "Deref"] pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] @@ -78,6 +79,7 @@ pub trait Deref { impl Deref for &T { type Target = T; + #[rustc_diagnostic_item = "noop_method_deref"] fn deref(&self) -> &T { *self } diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs index 2f2aa9a20f912..c97a87aebce41 100644 --- a/library/core/tests/clone.rs +++ b/library/core/tests/clone.rs @@ -1,5 +1,3 @@ -#![cfg_attr(not(bootstrap), allow(noop_method_call))] - #[test] fn test_borrowed_clone() { let x = 5; diff --git a/src/test/ui/issues/issue-11820.rs b/src/test/ui/issues/issue-11820.rs index dc6349b10ee58..7ffe9652797cf 100644 --- a/src/test/ui/issues/issue-11820.rs +++ b/src/test/ui/issues/issue-11820.rs @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![allow(noop_method_call)] - struct NoClone; fn main() { diff --git a/src/test/ui/lint/noop-method-call.rs b/src/test/ui/lint/noop-method-call.rs index 8e4b5bf4d12c7..9870c813572e3 100644 --- a/src/test/ui/lint/noop-method-call.rs +++ b/src/test/ui/lint/noop-method-call.rs @@ -1,15 +1,19 @@ // check-pass #![allow(unused)] +#![warn(noop_method_call)] -struct NonCloneType(T); +use std::borrow::Borrow; +use std::ops::Deref; + +struct PlainType(T); #[derive(Clone)] struct CloneType(T); fn main() { - let non_clone_type_ref = &NonCloneType(1u32); - let non_clone_type_ref_clone: &NonCloneType = non_clone_type_ref.clone(); + let non_clone_type_ref = &PlainType(1u32); + let non_clone_type_ref_clone: &PlainType = non_clone_type_ref.clone(); //~^ WARNING call to `.clone()` on a reference in this situation does nothing let clone_type_ref = &CloneType(1u32); @@ -20,15 +24,31 @@ fn main() { let clone_type_ref = &&CloneType(1u32); let clone_type_ref_clone: &CloneType = clone_type_ref.clone(); + let non_deref_type = &PlainType(1u32); + let non_deref_type_deref: &PlainType = non_deref_type.deref(); + //~^ WARNING call to `.deref()` on a reference in this situation does nothing + + // Dereferencing a &&T does not warn since it has collapsed the double reference + let non_deref_type = &&PlainType(1u32); + let non_deref_type_deref: &PlainType = non_deref_type.deref(); + + let non_borrow_type = &PlainType(1u32); + let non_borrow_type_borrow: &PlainType = non_borrow_type.borrow(); + //~^ WARNING call to `.borrow()` on a reference in this situation does nothing + + // Borrowing a &&T does not warn since it has collapsed the double reference + let non_borrow_type = &&PlainType(1u32); + let non_borrow_type_borrow: &PlainType = non_borrow_type.borrow(); + let xs = ["a", "b", "c"]; let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead } -fn generic(non_clone_type: &NonCloneType) { +fn generic(non_clone_type: &PlainType) { non_clone_type.clone(); } -fn non_generic(non_clone_type: &NonCloneType) { +fn non_generic(non_clone_type: &PlainType) { non_clone_type.clone(); //~^ WARNING call to `.clone()` on a reference in this situation does nothing } diff --git a/src/test/ui/lint/noop-method-call.stderr b/src/test/ui/lint/noop-method-call.stderr index 85a67f538407c..7f6f96bf1d142 100644 --- a/src/test/ui/lint/noop-method-call.stderr +++ b/src/test/ui/lint/noop-method-call.stderr @@ -1,19 +1,39 @@ warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:12:74 + --> $DIR/noop-method-call.rs:16:71 | -LL | let non_clone_type_ref_clone: &NonCloneType = non_clone_type_ref.clone(); - | ^^^^^^^^ unnecessary method call +LL | let non_clone_type_ref_clone: &PlainType = non_clone_type_ref.clone(); + | ^^^^^^^^ unnecessary method call | - = note: `#[warn(noop_method_call)]` on by default - = note: the type `&NonCloneType` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed +note: the lint level is defined here + --> $DIR/noop-method-call.rs:4:9 + | +LL | #![warn(noop_method_call)] + | ^^^^^^^^^^^^^^^^ + = note: the type `&PlainType` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed + +warning: call to `.deref()` on a reference in this situation does nothing + --> $DIR/noop-method-call.rs:28:63 + | +LL | let non_deref_type_deref: &PlainType = non_deref_type.deref(); + | ^^^^^^^^ unnecessary method call + | + = note: the type `&PlainType` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed + +warning: call to `.borrow()` on a reference in this situation does nothing + --> $DIR/noop-method-call.rs:36:66 + | +LL | let non_borrow_type_borrow: &PlainType = non_borrow_type.borrow(); + | ^^^^^^^^^ unnecessary method call + | + = note: the type `&PlainType` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed warning: call to `.clone()` on a reference in this situation does nothing - --> $DIR/noop-method-call.rs:32:19 + --> $DIR/noop-method-call.rs:52:19 | LL | non_clone_type.clone(); | ^^^^^^^^ unnecessary method call | - = note: the type `&NonCloneType` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed + = note: the type `&PlainType` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed -warning: 2 warnings emitted +warning: 4 warnings emitted diff --git a/src/test/ui/underscore-imports/cycle.rs b/src/test/ui/underscore-imports/cycle.rs index 987410fa84b20..bacf9b2d5a96a 100644 --- a/src/test/ui/underscore-imports/cycle.rs +++ b/src/test/ui/underscore-imports/cycle.rs @@ -14,6 +14,5 @@ mod y { pub fn main() { use x::*; - #[allow(noop_method_call)] (&0).deref(); } diff --git a/src/test/ui/underscore-imports/macro-expanded.rs b/src/test/ui/underscore-imports/macro-expanded.rs index 55e86e848558d..43f527bc9a408 100644 --- a/src/test/ui/underscore-imports/macro-expanded.rs +++ b/src/test/ui/underscore-imports/macro-expanded.rs @@ -3,7 +3,6 @@ // check-pass #![feature(decl_macro, rustc_attrs)] -#![allow(noop_method_call)] mod x { pub use std::ops::Not as _; diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.rs b/src/tools/clippy/tests/ui/unnecessary_clone.rs index ce26634a995d9..6770a7fac90fd 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.rs +++ b/src/tools/clippy/tests/ui/unnecessary_clone.rs @@ -1,7 +1,7 @@ // does not test any rustfixable lints #![warn(clippy::clone_on_ref_ptr)] -#![allow(unused, noop_method_call, clippy::redundant_clone, clippy::unnecessary_wraps)] +#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wraps)] use std::cell::RefCell; use std::rc::{self, Rc}; From 25637b228d68e9bdf2d3ce1ba421cbd115fcb81e Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 17 Feb 2021 10:06:23 +0100 Subject: [PATCH 61/67] Warn in doc test --- compiler/rustc_lint/src/noop_method_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 3a1b9c85fd1bd..479cc00199f6a 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -15,7 +15,7 @@ declare_lint! { /// /// ```rust /// # #![allow(unused)] - /// #![deny(noop_method_call)] + /// #![warn(noop_method_call)] /// struct Foo; /// let foo = &Foo; /// let clone: &Foo = foo.clone(); From 61114453ae55a93da437adb8fbf6b8a901f4fee5 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 19 Feb 2021 22:40:28 +0100 Subject: [PATCH 62/67] Add `-Z unpretty` flags for the AST --- compiler/rustc_driver/src/pretty.rs | 48 ++++++++++++++++----------- compiler/rustc_session/src/config.rs | 18 ++++++++-- compiler/rustc_session/src/options.rs | 2 ++ 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index 1dcc4d147acf2..38c493a920d26 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -9,7 +9,7 @@ use rustc_hir_pretty as pprust_hir; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::{self, TyCtxt}; use rustc_mir::util::{write_mir_graphviz, write_mir_pretty}; -use rustc_session::config::{Input, PpHirMode, PpMode, PpSourceMode}; +use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::FileName; @@ -391,24 +391,29 @@ pub fn print_after_parsing( ) { let (src, src_name) = get_source(input, sess); - let out = if let Source(s) = ppm { - // Silently ignores an identified node. - call_with_pp_support(&s, sess, None, move |annotation| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - let parse = &sess.parse_sess; - pprust::print_crate( - sess.source_map(), - krate, - src_name, - src, - annotation.pp_ann(), - false, - parse.edition, - ) - }) - } else { - unreachable!() + let out = match ppm { + Source(s) => { + // Silently ignores an identified node. + call_with_pp_support(&s, sess, None, move |annotation| { + debug!("pretty printing source code {:?}", s); + let sess = annotation.sess(); + let parse = &sess.parse_sess; + pprust::print_crate( + sess.source_map(), + krate, + src_name, + src, + annotation.pp_ann(), + false, + parse.edition, + ) + }) + } + AstTree(PpAstTreeMode::Normal) => { + debug!("pretty printing AST tree"); + format!("{:#?}", krate) + } + _ => unreachable!(), }; write_or_print(&out, ofile); @@ -447,6 +452,11 @@ pub fn print_after_hir_lowering<'tcx>( }) } + AstTree(PpAstTreeMode::Expanded) => { + debug!("pretty-printing expanded AST"); + format!("{:#?}", krate) + } + Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, krate| { debug!("pretty printing HIR {:?}", s); let sess = annotation.sess(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a3900ebcea99c..77a9a2b227ca0 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2066,6 +2066,8 @@ fn parse_pretty( ("expanded", _) => Source(PpSourceMode::Expanded), ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified), ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene), + ("ast-tree", true) => AstTree(PpAstTreeMode::Normal), + ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded), ("hir", true) => Hir(PpHirMode::Normal), ("hir,identified", true) => Hir(PpHirMode::Identified), ("hir,typed", true) => Hir(PpHirMode::Typed), @@ -2080,8 +2082,8 @@ fn parse_pretty( "argument to `unpretty` must be one of `normal`, \ `expanded`, `identified`, `expanded,identified`, \ `expanded,hygiene`, `everybody_loops`, \ - `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \ - `mir` or `mir-cfg`; got {}", + `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ + `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}", name ), ); @@ -2233,6 +2235,14 @@ pub enum PpSourceMode { ExpandedHygiene, } +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum PpAstTreeMode { + /// `-Zunpretty=ast` + Normal, + /// `-Zunpretty=ast,expanded` + Expanded, +} + #[derive(Copy, Clone, PartialEq, Debug)] pub enum PpHirMode { /// `-Zunpretty=hir` @@ -2248,6 +2258,7 @@ pub enum PpMode { /// Options that print the source code, i.e. /// `--pretty` and `-Zunpretty=everybody_loops` Source(PpSourceMode), + AstTree(PpAstTreeMode), /// Options that print the HIR, i.e. `-Zunpretty=hir` Hir(PpHirMode), /// `-Zunpretty=hir-tree` @@ -2263,9 +2274,10 @@ impl PpMode { use PpMode::*; use PpSourceMode::*; match *self { - Source(Normal | Identified) => false, + Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false, Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene) + | AstTree(PpAstTreeMode::Expanded) | Hir(_) | HirTree | Mir diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index e2b6b1dc2437b..6e7d39547a143 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1158,6 +1158,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, `expanded`, `expanded,identified`, `expanded,hygiene` (with internal representations), `everybody_loops` (all function bodies replaced with `loop {}`), + `ast-tree` (raw AST before expansion), + `ast-tree,expanded` (raw AST after expansion), `hir` (the HIR), `hir,identified`, `hir,typed` (HIR with types for each node), `hir-tree` (dump the raw HIR), From 950f12119ef724156a9a4e17e1b375eb28c6af11 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 3 Mar 2021 20:04:20 +0300 Subject: [PATCH 63/67] Update library/alloc/src/vec/mod.rs Co-authored-by: Ralf Jung --- library/alloc/src/vec/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ff401b33832ce..4b992d1756bef 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1950,7 +1950,7 @@ impl Vec { // SAFETY: // - `ptr` is guaranteed to be valid for `len` elements - // - `spare_ptr` is pointing one element past the buffer, so it doesn't overlap with `initialized` slice + // - `spare_ptr` is pointing one element past the buffer, so it doesn't overlap with `initialized` unsafe { let initialized = slice::from_raw_parts_mut(ptr, self.len); let spare = slice::from_raw_parts_mut(spare_ptr, spare_len); From 5461ee0b2632ccd912d316a68dd63a5b45125f57 Mon Sep 17 00:00:00 2001 From: "katelyn a. martin" Date: Thu, 27 Aug 2020 11:49:18 -0400 Subject: [PATCH 64/67] rustc_target: add "unwind" payloads to `Abi` ### Overview This commit begins the implementation work for RFC 2945. For more information, see the rendered RFC [1] and tracking issue [2]. A boolean `unwind` payload is added to the `C`, `System`, `Stdcall`, and `Thiscall` variants, marking whether unwinding across FFI boundaries is acceptable. The cases where each of these variants' `unwind` member is true correspond with the `C-unwind`, `system-unwind`, `stdcall-unwind`, and `thiscall-unwind` ABI strings introduced in RFC 2945 [3]. ### Feature Gate and Unstable Book This commit adds a `c_unwind` feature gate for the new ABI strings. Tests for this feature gate are included in `src/test/ui/c-unwind/`, which ensure that this feature gate works correctly for each of the new ABIs. A new language features entry in the unstable book is added as well. ### Further Work To Be Done This commit does not proceed to implement the new unwinding ABIs, and is intentionally scoped specifically to *defining* the ABIs and their feature flag. ### One Note on Test Churn This will lead to some test churn, in re-blessing hash tests, as the deleted comment in `src/librustc_target/spec/abi.rs` mentioned, because we can no longer guarantee the ordering of the `Abi` variants. While this is a downside, this decision was made bearing in mind that RFC 2945 states the following, in the "Other `unwind` Strings" section [3]: > More unwind variants of existing ABI strings may be introduced, > with the same semantics, without an additional RFC. Adding a new variant for each of these cases, rather than specifying a payload for a given ABI, would quickly become untenable, and make working with the `Abi` enum prone to mistakes. This approach encodes the unwinding information *into* a given ABI, to account for the future possibility of other `-unwind` ABI strings. ### Ignore Directives `ignore-*` directives are used in two of our `*-unwind` ABI test cases. Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases ignore architectures that do not support `stdcall` and `thiscall`, respectively. These directives are cribbed from `src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and `src/test/ui/extern/extern-thiscall.rs` for `thiscall`. This would otherwise fail on some targets, see: https://github.com/rust-lang-ci/rust/commit/fcf697f90206e9c87b39d494f94ab35d976bfc60 ### Footnotes [1]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md [2]: https://github.com/rust-lang/rust/issues/74990 [3]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md#other-unwind-abi-strings --- compiler/rustc_ast_lowering/src/item.rs | 8 +-- compiler/rustc_ast_passes/src/feature_gate.rs | 32 +++++++++ .../rustc_codegen_cranelift/src/abi/mod.rs | 2 +- compiler/rustc_feature/src/active.rs | 3 + compiler/rustc_middle/src/ty/layout.rs | 8 +-- .../rustc_mir/src/interpret/terminator.rs | 6 +- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_symbol_mangling/src/v0.rs | 2 +- compiler/rustc_target/src/spec/abi.rs | 65 +++++++++++++++---- compiler/rustc_target/src/spec/arm_base.rs | 11 +++- .../src/spec/mipsel_unknown_none.rs | 6 +- compiler/rustc_target/src/spec/mod.rs | 19 ++++-- .../src/spec/nvptx64_nvidia_cuda.rs | 6 +- compiler/rustc_target/src/spec/riscv_base.rs | 6 +- compiler/rustc_typeck/src/collect.rs | 2 +- compiler/rustc_typeck/src/lib.rs | 21 +++--- .../src/language-features/c-unwind.md | 14 ++++ src/test/ui/codemap_tests/unicode.stderr | 2 +- src/test/ui/parser/issue-8537.stderr | 2 +- src/test/ui/symbol-names/impl1.rs | 6 +- .../feature-gate-c-unwind-enabled.rs | 12 ++++ .../ui/unwind-abis/feature-gate-c-unwind.rs | 9 +++ .../unwind-abis/feature-gate-c-unwind.stderr | 12 ++++ .../feature-gate-stdcall-unwind.rs | 13 ++++ .../feature-gate-stdcall-unwind.stderr | 12 ++++ .../unwind-abis/feature-gate-system-unwind.rs | 9 +++ .../feature-gate-system-unwind.stderr | 12 ++++ .../feature-gate-thiscall-unwind.rs | 13 ++++ .../feature-gate-thiscall-unwind.stderr | 12 ++++ 29 files changed, 274 insertions(+), 52 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/c-unwind.md create mode 100644 src/test/ui/unwind-abis/feature-gate-c-unwind-enabled.rs create mode 100644 src/test/ui/unwind-abis/feature-gate-c-unwind.rs create mode 100644 src/test/ui/unwind-abis/feature-gate-c-unwind.stderr create mode 100644 src/test/ui/unwind-abis/feature-gate-stdcall-unwind.rs create mode 100644 src/test/ui/unwind-abis/feature-gate-stdcall-unwind.stderr create mode 100644 src/test/ui/unwind-abis/feature-gate-system-unwind.rs create mode 100644 src/test/ui/unwind-abis/feature-gate-system-unwind.stderr create mode 100644 src/test/ui/unwind-abis/feature-gate-thiscall-unwind.rs create mode 100644 src/test/ui/unwind-abis/feature-gate-thiscall-unwind.stderr diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8b740b7774089..2267f09ec1f11 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -322,10 +322,10 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ItemKind::ForeignMod(ref fm) => { if fm.abi.is_none() { - self.maybe_lint_missing_abi(span, id, abi::Abi::C); + self.maybe_lint_missing_abi(span, id, abi::Abi::C { unwind: false }); } hir::ItemKind::ForeignMod { - abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)), + abi: fm.abi.map_or(abi::Abi::C { unwind: false }, |abi| self.lower_abi(abi)), items: self .arena .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), @@ -1322,8 +1322,8 @@ impl<'hir> LoweringContext<'_, 'hir> { match ext { Extern::None => abi::Abi::Rust, Extern::Implicit => { - self.maybe_lint_missing_abi(span, id, abi::Abi::C); - abi::Abi::C + self.maybe_lint_missing_abi(span, id, abi::Abi::C { unwind: false }); + abi::Abi::C { unwind: false } } Extern::Explicit(abi) => self.lower_abi(abi), } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 474ec2b589b71..acfbec6fa21b5 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -164,6 +164,38 @@ impl<'a> PostExpansionVisitor<'a> { "C-cmse-nonsecure-call ABI is experimental and subject to change" ); } + "C-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "C-unwind ABI is experimental and subject to change" + ); + } + "stdcall-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "stdcall-unwind ABI is experimental and subject to change" + ); + } + "system-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "system-unwind ABI is experimental and subject to change" + ); + } + "thiscall-unwind" => { + gate_feature_post!( + &self, + c_unwind, + span, + "thiscall-unwind ABI is experimental and subject to change" + ); + } abi => self .sess .parse_sess diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index b2647e6c8d384..83bb1d0172fbb 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -542,7 +542,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( // FIXME find a cleaner way to support varargs if fn_sig.c_variadic { - if fn_sig.abi != Abi::C { + if !matches!(fn_sig.abi, Abi::C { .. }) { fx.tcx.sess.span_fatal( span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi), diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 8ee995a59d80d..95ae6a1ac9a26 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -644,6 +644,9 @@ declare_features! ( /// Allows associated types in inherent impls. (active, inherent_associated_types, "1.52.0", Some(8995), None), + /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries. + (active, c_unwind, "1.52.0", Some(74990), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6d2ab0e5f5a80..2f5380861c495 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2654,14 +2654,14 @@ where RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, // It's the ABI's job to select this, not ours. - System => bug!("system abi should be selected elsewhere"), + System { .. } => bug!("system abi should be selected elsewhere"), EfiApi => bug!("eficall abi should be selected elsewhere"), - Stdcall => Conv::X86Stdcall, + Stdcall { .. } => Conv::X86Stdcall, Fastcall => Conv::X86Fastcall, Vectorcall => Conv::X86VectorCall, - Thiscall => Conv::X86ThisCall, - C => Conv::C, + Thiscall { .. } => Conv::X86ThisCall, + C { .. } => Conv::C, Unadjusted => Conv::C, Win64 => Conv::X86_64Win64, SysV64 => Conv::X86_64SysV, diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index 0807949a2d91b..4aa1360d53539 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -248,9 +248,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; if normalize_abi(caller_abi) != normalize_abi(callee_abi) { throw_ub_format!( - "calling a function with ABI {:?} using caller ABI {:?}", - callee_abi, - caller_abi + "calling a function with ABI {} using caller ABI {}", + callee_abi.name(), + caller_abi.name() ) } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 27bb45bcc8512..6eb5a40fba92c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -328,6 +328,7 @@ symbols! { bridge, bswap, c_str, + c_unwind, c_variadic, call, call_mut, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index bbf7ecc39cfd9..12c0a147990fa 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -440,7 +440,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } match sig.abi { Abi::Rust => {} - Abi::C => cx.push("KC"), + Abi::C { unwind: false } => cx.push("KC"), abi => { cx.push("K"); let name = abi.name(); diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index 65e8a4e8db2ad..f7f9c30d3b7a6 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -8,24 +8,21 @@ mod tests; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)] #[derive(HashStable_Generic, Encodable, Decodable)] pub enum Abi { - // N.B., this ordering MUST match the AbiDatas array below. - // (This is ensured by the test indices_are_correct().) - // Multiplatform / generic ABIs // // These ABIs come first because every time we add a new ABI, we // have to re-bless all the hashing tests. These are used in many // places, so giving them stable values reduces test churn. The // specific values are meaningless. - Rust = 0, - C = 1, + Rust, + C { unwind: bool }, // Single platform ABIs Cdecl, - Stdcall, + Stdcall { unwind: bool }, Fastcall, Vectorcall, - Thiscall, + Thiscall { unwind: bool }, Aapcs, Win64, SysV64, @@ -39,7 +36,7 @@ pub enum Abi { CCmseNonSecureCall, // Multiplatform / generic ABIs - System, + System { unwind: bool }, RustIntrinsic, RustCall, PlatformIntrinsic, @@ -61,13 +58,16 @@ pub struct AbiData { const AbiDatas: &[AbiData] = &[ // Cross-platform ABIs AbiData { abi: Abi::Rust, name: "Rust", generic: true }, - AbiData { abi: Abi::C, name: "C", generic: true }, + AbiData { abi: Abi::C { unwind: false }, name: "C", generic: true }, + AbiData { abi: Abi::C { unwind: true }, name: "C-unwind", generic: true }, // Platform-specific ABIs AbiData { abi: Abi::Cdecl, name: "cdecl", generic: false }, - AbiData { abi: Abi::Stdcall, name: "stdcall", generic: false }, + AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall", generic: false }, + AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind", generic: false }, AbiData { abi: Abi::Fastcall, name: "fastcall", generic: false }, AbiData { abi: Abi::Vectorcall, name: "vectorcall", generic: false }, - AbiData { abi: Abi::Thiscall, name: "thiscall", generic: false }, + AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall", generic: false }, + AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind", generic: false }, AbiData { abi: Abi::Aapcs, name: "aapcs", generic: false }, AbiData { abi: Abi::Win64, name: "win64", generic: false }, AbiData { abi: Abi::SysV64, name: "sysv64", generic: false }, @@ -84,7 +84,8 @@ const AbiDatas: &[AbiData] = &[ }, AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call", generic: false }, // Cross-platform ABIs - AbiData { abi: Abi::System, name: "system", generic: true }, + AbiData { abi: Abi::System { unwind: false }, name: "system", generic: true }, + AbiData { abi: Abi::System { unwind: true }, name: "system-unwind", generic: true }, AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true }, AbiData { abi: Abi::RustCall, name: "rust-call", generic: true }, AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true }, @@ -103,7 +104,41 @@ pub fn all_names() -> Vec<&'static str> { impl Abi { #[inline] pub fn index(self) -> usize { - self as usize + // N.B., this ordering MUST match the AbiDatas array above. + // (This is ensured by the test indices_are_correct().) + use Abi::*; + match self { + // Cross-platform ABIs + Rust => 0, + C { unwind: false } => 1, + C { unwind: true } => 2, + // Platform-specific ABIs + Cdecl => 3, + Stdcall { unwind: false } => 4, + Stdcall { unwind: true } => 5, + Fastcall => 6, + Vectorcall => 7, + Thiscall { unwind: false } => 8, + Thiscall { unwind: true } => 9, + Aapcs => 10, + Win64 => 11, + SysV64 => 12, + PtxKernel => 13, + Msp430Interrupt => 14, + X86Interrupt => 15, + AmdGpuKernel => 16, + EfiApi => 17, + AvrInterrupt => 18, + AvrNonBlockingInterrupt => 19, + CCmseNonSecureCall => 20, + // Cross-platform ABIs + System { unwind: false } => 21, + System { unwind: true } => 22, + RustIntrinsic => 23, + RustCall => 24, + PlatformIntrinsic => 25, + Unadjusted => 26, + } } #[inline] @@ -122,6 +157,8 @@ impl Abi { impl fmt::Display for Abi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\"{}\"", self.name()) + match self { + abi => write!(f, "\"{}\"", abi.name()), + } } } diff --git a/compiler/rustc_target/src/spec/arm_base.rs b/compiler/rustc_target/src/spec/arm_base.rs index b74d80dc6bb2b..01f573313c97f 100644 --- a/compiler/rustc_target/src/spec/arm_base.rs +++ b/compiler/rustc_target/src/spec/arm_base.rs @@ -2,5 +2,14 @@ use crate::spec::abi::Abi; // All the calling conventions trigger an assertion(Unsupported calling convention) in llvm on arm pub fn unsupported_abis() -> Vec { - vec![Abi::Stdcall, Abi::Fastcall, Abi::Vectorcall, Abi::Thiscall, Abi::Win64, Abi::SysV64] + vec![ + Abi::Stdcall { unwind: false }, + Abi::Stdcall { unwind: true }, + Abi::Fastcall, + Abi::Vectorcall, + Abi::Thiscall { unwind: false }, + Abi::Thiscall { unwind: true }, + Abi::Win64, + Abi::SysV64, + ] } diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs index 0f9d3c3de1543..110c8dd80ea77 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs @@ -23,10 +23,12 @@ pub fn target() -> Target { panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, unsupported_abis: vec![ - Abi::Stdcall, + Abi::Stdcall { unwind: false }, + Abi::Stdcall { unwind: true }, Abi::Fastcall, Abi::Vectorcall, - Abi::Thiscall, + Abi::Thiscall { unwind: false }, + Abi::Thiscall { unwind: true }, Abi::Win64, Abi::SysV64, ], diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 039e9a8b2745f..4e8c0c03696d9 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1282,24 +1282,31 @@ impl Target { /// Given a function ABI, turn it into the correct ABI for this target. pub fn adjust_abi(&self, abi: Abi) -> Abi { match abi { - Abi::System => { + Abi::System { unwind } => { if self.is_like_windows && self.arch == "x86" { - Abi::Stdcall + Abi::Stdcall { unwind } } else { - Abi::C + Abi::C { unwind } } } // These ABI kinds are ignored on non-x86 Windows targets. // See https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions // and the individual pages for __stdcall et al. - Abi::Stdcall | Abi::Fastcall | Abi::Vectorcall | Abi::Thiscall => { - if self.is_like_windows && self.arch != "x86" { Abi::C } else { abi } + Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => { + if self.is_like_windows && self.arch != "x86" { Abi::C { unwind } } else { abi } + } + Abi::Fastcall | Abi::Vectorcall => { + if self.is_like_windows && self.arch != "x86" { + Abi::C { unwind: false } + } else { + abi + } } Abi::EfiApi => { if self.arch == "x86_64" { Abi::Win64 } else { - Abi::C + Abi::C { unwind: false } } } abi => abi, diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs index 3c9c7d578fbd4..15d8e4843f976 100644 --- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs @@ -49,10 +49,12 @@ pub fn target() -> Target { // create the tests for this. unsupported_abis: vec![ Abi::Cdecl, - Abi::Stdcall, + Abi::Stdcall { unwind: false }, + Abi::Stdcall { unwind: true }, Abi::Fastcall, Abi::Vectorcall, - Abi::Thiscall, + Abi::Thiscall { unwind: false }, + Abi::Thiscall { unwind: true }, Abi::Aapcs, Abi::Win64, Abi::SysV64, diff --git a/compiler/rustc_target/src/spec/riscv_base.rs b/compiler/rustc_target/src/spec/riscv_base.rs index 64cf890037e51..5bcbb2e621bd0 100644 --- a/compiler/rustc_target/src/spec/riscv_base.rs +++ b/compiler/rustc_target/src/spec/riscv_base.rs @@ -5,10 +5,12 @@ use crate::spec::abi::Abi; pub fn unsupported_abis() -> Vec { vec![ Abi::Cdecl, - Abi::Stdcall, + Abi::Stdcall { unwind: false }, + Abi::Stdcall { unwind: true }, Abi::Fastcall, Abi::Vectorcall, - Abi::Thiscall, + Abi::Thiscall { unwind: false }, + Abi::Thiscall { unwind: true }, Abi::Aapcs, Abi::Win64, Abi::SysV64, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 3881d55ef9169..a175da3270638 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2666,7 +2666,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } else if tcx.sess.check_name(attr, sym::used) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; } else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) { - if tcx.fn_sig(id).abi() != abi::Abi::C { + if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) { struct_span_err!( tcx.sess, attr.span, diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 6ddc26efeae35..fb864c5b4a7d7 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -118,14 +118,19 @@ use astconv::AstConv; use bounds::Bounds; fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { - if decl.c_variadic && !(abi == Abi::C || abi == Abi::Cdecl) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0045, - "C-variadic function must have C or cdecl calling convention" - ); - err.span_label(span, "C-variadics require C or cdecl calling convention").emit(); + match (decl.c_variadic, abi) { + // The function has the correct calling convention, or isn't a "C-variadic" function. + (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl) => {} + // The function is a "C-variadic" function with an incorrect calling convention. + (true, _) => { + let mut err = struct_span_err!( + tcx.sess, + span, + E0045, + "C-variadic function must have C or cdecl calling convention" + ); + err.span_label(span, "C-variadics require C or cdecl calling convention").emit(); + } } } diff --git a/src/doc/unstable-book/src/language-features/c-unwind.md b/src/doc/unstable-book/src/language-features/c-unwind.md new file mode 100644 index 0000000000000..c1705d59acc21 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/c-unwind.md @@ -0,0 +1,14 @@ +# `c_unwind` + +The tracking issue for this feature is: [#74990] + +[#74990]: https://github.com/rust-lang/rust/issues/74990 + +------------------------ + +Introduces a new ABI string, "C-unwind", to enable unwinding from other +languages (such as C++) into Rust frames and from Rust into other languages. + +See [RFC 2945] for more information. + +[RFC 2945]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 61c3f4f1c9847..b7ba4fa46d92b 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́` LL | extern "路濫狼á́́" fn foo() {} | ^^^^^^^^^ invalid ABI | - = help: valid ABIs: Rust, C, cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error diff --git a/src/test/ui/parser/issue-8537.stderr b/src/test/ui/parser/issue-8537.stderr index 3f63c08021098..85e2b77d867b9 100644 --- a/src/test/ui/parser/issue-8537.stderr +++ b/src/test/ui/parser/issue-8537.stderr @@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize` LL | "invalid-ab_isize" | ^^^^^^^^^^^^^^^^^^ invalid ABI | - = help: valid ABIs: Rust, C, cdecl, stdcall, fastcall, vectorcall, thiscall, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted + = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted error: aborting due to previous error diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 24bdf6d669e88..7dd74bd229d3f 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -4,7 +4,7 @@ //[legacy]compile-flags: -Z symbol-mangling-version=legacy //[v0]compile-flags: -Z symbol-mangling-version=v0 //[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH" -//[legacy]normalize-stderr-64bit: "h310ea0259fc3d32d" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-64bit: "hd949d7797008991f" -> "SYMBOL_HASH" #![feature(auto_traits, rustc_attrs)] #![allow(dead_code)] @@ -75,3 +75,7 @@ fn main() { } }; } + +// FIXME(katie): The 32-bit symbol hash probably needs updating as well, but I'm slightly unsure +// about how to do that. This comment is here so that we don't break the test due to error messages +// including incorrect line numbers. diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind-enabled.rs b/src/test/ui/unwind-abis/feature-gate-c-unwind-enabled.rs new file mode 100644 index 0000000000000..6ff5dbda2d560 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-c-unwind-enabled.rs @@ -0,0 +1,12 @@ +// Test that the "C-unwind" ABI is feature-gated, and *can* be used when the +// `c_unwind` feature gate is enabled. + +// check-pass + +#![feature(c_unwind)] + +extern "C-unwind" fn f() {} + +fn main() { + f(); +} diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs new file mode 100644 index 0000000000000..f02a368d4e097 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs @@ -0,0 +1,9 @@ +// Test that the "C-unwind" ABI is feature-gated, and cannot be used when the +// `c_unwind` feature gate is not used. + +extern "C-unwind" fn f() {} +//~^ ERROR C-unwind ABI is experimental and subject to change [E0658] + +fn main() { + f(); +} diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr new file mode 100644 index 0000000000000..f4c785a235f67 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr @@ -0,0 +1,12 @@ +error[E0658]: C-unwind ABI is experimental and subject to change + --> $DIR/feature-gate-c-unwind.rs:4:8 + | +LL | extern "C-unwind" fn f() {} + | ^^^^^^^^^^ + | + = note: see issue #74990 for more information + = help: add `#![feature(c_unwind)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unwind-abis/feature-gate-stdcall-unwind.rs b/src/test/ui/unwind-abis/feature-gate-stdcall-unwind.rs new file mode 100644 index 0000000000000..7d4dc8c9343f1 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-stdcall-unwind.rs @@ -0,0 +1,13 @@ +// ignore-arm stdcall isn't supported +// ignore-aarch64 stdcall isn't supported +// ignore-riscv64 stdcall isn't supported + +// Test that the "stdcall-unwind" ABI is feature-gated, and cannot be used when +// the `c_unwind` feature gate is not used. + +extern "stdcall-unwind" fn f() {} +//~^ ERROR stdcall-unwind ABI is experimental and subject to change [E0658] + +fn main() { + f(); +} diff --git a/src/test/ui/unwind-abis/feature-gate-stdcall-unwind.stderr b/src/test/ui/unwind-abis/feature-gate-stdcall-unwind.stderr new file mode 100644 index 0000000000000..e3d569f464f87 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-stdcall-unwind.stderr @@ -0,0 +1,12 @@ +error[E0658]: stdcall-unwind ABI is experimental and subject to change + --> $DIR/feature-gate-stdcall-unwind.rs:8:8 + | +LL | extern "stdcall-unwind" fn f() {} + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #74990 for more information + = help: add `#![feature(c_unwind)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unwind-abis/feature-gate-system-unwind.rs b/src/test/ui/unwind-abis/feature-gate-system-unwind.rs new file mode 100644 index 0000000000000..26c2de4e81767 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-system-unwind.rs @@ -0,0 +1,9 @@ +// Test that the "system-unwind" ABI is feature-gated, and cannot be used when +// the `c_unwind` feature gate is not used. + +extern "system-unwind" fn f() {} +//~^ ERROR system-unwind ABI is experimental and subject to change [E0658] + +fn main() { + f(); +} diff --git a/src/test/ui/unwind-abis/feature-gate-system-unwind.stderr b/src/test/ui/unwind-abis/feature-gate-system-unwind.stderr new file mode 100644 index 0000000000000..87877336475b4 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-system-unwind.stderr @@ -0,0 +1,12 @@ +error[E0658]: system-unwind ABI is experimental and subject to change + --> $DIR/feature-gate-system-unwind.rs:4:8 + | +LL | extern "system-unwind" fn f() {} + | ^^^^^^^^^^^^^^^ + | + = note: see issue #74990 for more information + = help: add `#![feature(c_unwind)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/unwind-abis/feature-gate-thiscall-unwind.rs b/src/test/ui/unwind-abis/feature-gate-thiscall-unwind.rs new file mode 100644 index 0000000000000..2f4cefccc1967 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-thiscall-unwind.rs @@ -0,0 +1,13 @@ +// ignore-arm thiscall isn't supported +// ignore-aarch64 thiscall isn't supported +// ignore-riscv64 thiscall isn't supported + +// Test that the "thiscall-unwind" ABI is feature-gated, and cannot be used when +// the `c_unwind` feature gate is not used. + +extern "thiscall-unwind" fn f() {} +//~^ ERROR thiscall-unwind ABI is experimental and subject to change [E0658] + +fn main() { + f(); +} diff --git a/src/test/ui/unwind-abis/feature-gate-thiscall-unwind.stderr b/src/test/ui/unwind-abis/feature-gate-thiscall-unwind.stderr new file mode 100644 index 0000000000000..b103bb8d56585 --- /dev/null +++ b/src/test/ui/unwind-abis/feature-gate-thiscall-unwind.stderr @@ -0,0 +1,12 @@ +error[E0658]: thiscall-unwind ABI is experimental and subject to change + --> $DIR/feature-gate-thiscall-unwind.rs:8:8 + | +LL | extern "thiscall-unwind" fn f() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #74990 for more information + = help: add `#![feature(c_unwind)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From 9a007cfdc0857a4ad0601e2e130ef53d158493ee Mon Sep 17 00:00:00 2001 From: "katelyn a. martin" Date: Thu, 10 Sep 2020 13:38:39 -0400 Subject: [PATCH 65/67] implement unwinding abi's (RFC 2945) ### Changes This commit implements unwind ABI's, specified in RFC 2945. We adjust the `rustc_middle::ty::layout::fn_can_unwind` function, used to compute whether or not a `FnAbi` object represents a function that should be able to unwind when `panic=unwind` is in use. Changes are also made to `rustc_mir_build::build::should_abort_on_panic` so that the function ABI is used to determind whether it should abort, assuming that the `panic=unwind` strategy is being used, and no explicit unwind attribute was provided. ### Tests Unit tests, checking that the behavior is correct for `C-unwind`, `stdcall-unwind`, `system-unwind`, and `thiscall-unwind`, are included. These alternative `unwind` ABI strings are specified in RFC 2945, in the "_Other `unwind` ABI strings_" section. Additionally, a test case is included to assert that the LLVM IR generated for an external function defined with the `C-unwind` ABI will be appropriately labeled with the `nounwind` LLVM attribute when the `panic=abort` compilation flag is used. ### Ignore Directives This commit uses `ignore-*` directives in two of our `*-unwind` ABI test cases. Specifically, the `stdcall-unwind` and `thiscall-unwind` test cases ignore architectures that do not support `stdcall` and `thiscall`, respectively. These directives are cribbed from `src/test/ui/c-variadic/variadic-ffi-1.rs` for `stdcall`, and `src/test/ui/extern/extern-thiscall.rs` for `thiscall`. --- compiler/rustc_middle/src/ty/layout.rs | 29 +++++++++------- compiler/rustc_mir_build/src/build/mod.rs | 22 ++++++++++--- .../unwind-abis/c-unwind-abi-panic-abort.rs | 18 ++++++++++ src/test/codegen/unwind-abis/c-unwind-abi.rs | 29 ++++++++++++++++ .../codegen/unwind-abis/stdcall-unwind-abi.rs | 32 ++++++++++++++++++ .../codegen/unwind-abis/system-unwind-abi.rs | 29 ++++++++++++++++ .../unwind-abis/thiscall-unwind-abi.rs | 33 +++++++++++++++++++ 7 files changed, 176 insertions(+), 16 deletions(-) create mode 100644 src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs create mode 100644 src/test/codegen/unwind-abis/c-unwind-abi.rs create mode 100644 src/test/codegen/unwind-abis/stdcall-unwind-abi.rs create mode 100644 src/test/codegen/unwind-abis/system-unwind-abi.rs create mode 100644 src/test/codegen/unwind-abis/thiscall-unwind-abi.rs diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 2f5380861c495..ee2dffd8baeb9 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2562,6 +2562,7 @@ fn fn_can_unwind( panic_strategy: PanicStrategy, codegen_fn_attr_flags: CodegenFnAttrFlags, call_conv: Conv, + abi: SpecAbi, ) -> bool { if panic_strategy != PanicStrategy::Unwind { // In panic=abort mode we assume nothing can unwind anywhere, so @@ -2586,17 +2587,16 @@ fn fn_can_unwind( // // 2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`). // - // Foreign items (case 1) are assumed to not unwind; it is - // UB otherwise. (At least for now; see also - // rust-lang/rust#63909 and Rust RFC 2753.) - // - // Items defined in Rust with non-Rust ABIs (case 2) are also - // not supposed to unwind. Whether this should be enforced - // (versus stating it is UB) and *how* it would be enforced - // is currently under discussion; see rust-lang/rust#58794. - // - // In either case, we mark item as explicitly nounwind. - false + // In both of these cases, we should refer to the ABI to determine whether or not we + // should unwind. See Rust RFC 2945 for more information on this behavior, here: + // https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md + use SpecAbi::*; + match abi { + C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => { + unwind + } + _ => false, + } } } } @@ -2823,7 +2823,12 @@ where c_variadic: sig.c_variadic, fixed_count: inputs.len(), conv, - can_unwind: fn_can_unwind(cx.tcx().sess.panic_strategy(), codegen_fn_attr_flags, conv), + can_unwind: fn_can_unwind( + cx.tcx().sess.panic_strategy(), + codegen_fn_attr_flags, + conv, + sig.abi, + ), }; fn_abi.adjust_for_abi(cx, sig.abi); debug!("FnAbi::new_internal = {:?}", fn_abi); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 5f6c8d26402ed..dec26278290d9 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -546,7 +546,7 @@ macro_rules! unpack { }}; } -fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, _abi: Abi) -> bool { +fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, abi: Abi) -> bool { // Validate `#[unwind]` syntax regardless of platform-specific panic strategy. let attrs = &tcx.get_attrs(fn_def_id.to_def_id()); let unwind_attr = attr::find_unwind_attr(&tcx.sess, attrs); @@ -556,12 +556,26 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, _abi: Abi) -> b return false; } - // This is a special case: some functions have a C abi but are meant to - // unwind anyway. Don't stop them. match unwind_attr { - None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)` + // If an `#[unwind]` attribute was found, we should adhere to it. Some(UnwindAttr::Allowed) => false, Some(UnwindAttr::Aborts) => true, + // If no attribute was found and the panic strategy is `unwind`, then we should examine + // the function's ABI string to determine whether it should abort upon panic. + None => { + use Abi::*; + match abi { + // In the case of ABI's that have an `-unwind` equivalent, check whether the ABI + // permits unwinding. If so, we should not abort. Otherwise, we should. + C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => { + !unwind + } + // Rust and `rust-call` functions are allowed to unwind, and should not abort. + Rust | RustCall => false, + // Other ABI's should abort. + _ => true, + } + } } } diff --git a/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs b/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs new file mode 100644 index 0000000000000..afd65ff6741a6 --- /dev/null +++ b/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs @@ -0,0 +1,18 @@ +// compile-flags: -C panic=abort -C opt-level=0 + +// Test that `nounwind` atributes are applied to `C-unwind` extern functions when the +// code is compiled with `panic=abort`. We disable optimizations above to prevent LLVM from +// inferring the attribute. + +#![crate_type = "lib"] +#![feature(c_unwind)] + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "C-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make sure that the LLVM attributes for this functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } diff --git a/src/test/codegen/unwind-abis/c-unwind-abi.rs b/src/test/codegen/unwind-abis/c-unwind-abi.rs new file mode 100644 index 0000000000000..f157653675322 --- /dev/null +++ b/src/test/codegen/unwind-abis/c-unwind-abi.rs @@ -0,0 +1,29 @@ +// compile-flags: -C opt-level=0 + +// Test that `nounwind` atributes are correctly applied to exported `C` and `C-unwind` extern +// functions. `C-unwind` functions MUST NOT have this attribute. We disable optimizations above +// to prevent LLVM from inferring the attribute. + +#![crate_type = "lib"] +#![feature(c_unwind)] + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "C" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "C-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/codegen/unwind-abis/stdcall-unwind-abi.rs b/src/test/codegen/unwind-abis/stdcall-unwind-abi.rs new file mode 100644 index 0000000000000..ed804ca278d2d --- /dev/null +++ b/src/test/codegen/unwind-abis/stdcall-unwind-abi.rs @@ -0,0 +1,32 @@ +// compile-flags: -C opt-level=0 +// ignore-arm stdcall isn't supported +// ignore-aarch64 stdcall isn't supported +// ignore-riscv64 stdcall isn't supported + +// Test that `nounwind` atributes are correctly applied to exported `stdcall` and `stdcall-unwind` +// extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable +// optimizations above to prevent LLVM from inferring the attribute. + +#![crate_type = "lib"] +#![feature(c_unwind)] + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "stdcall" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "stdcall-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/codegen/unwind-abis/system-unwind-abi.rs b/src/test/codegen/unwind-abis/system-unwind-abi.rs new file mode 100644 index 0000000000000..c4d51328352c0 --- /dev/null +++ b/src/test/codegen/unwind-abis/system-unwind-abi.rs @@ -0,0 +1,29 @@ +// compile-flags: -C opt-level=0 + +// Test that `nounwind` atributes are correctly applied to exported `system` and `system-unwind` +// extern functions. `system-unwind` functions MUST NOT have this attribute. We disable +// optimizations above to prevent LLVM from inferring the attribute. + +#![crate_type = "lib"] +#![feature(c_unwind)] + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "system" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "system-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } diff --git a/src/test/codegen/unwind-abis/thiscall-unwind-abi.rs b/src/test/codegen/unwind-abis/thiscall-unwind-abi.rs new file mode 100644 index 0000000000000..aaa63ae55c3ac --- /dev/null +++ b/src/test/codegen/unwind-abis/thiscall-unwind-abi.rs @@ -0,0 +1,33 @@ +// compile-flags: -C opt-level=0 +// ignore-arm thiscall isn't supported +// ignore-aarch64 thiscall isn't supported +// ignore-riscv64 thiscall isn't supported + +// Test that `nounwind` atributes are correctly applied to exported `thiscall` and +// `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We +// disable optimizations above to prevent LLVM from inferring the attribute. + +#![crate_type = "lib"] +#![feature(abi_thiscall)] +#![feature(c_unwind)] + +// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 { +#[no_mangle] +pub extern "thiscall" fn rust_item_that_cannot_unwind() { +} + +// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 { +#[no_mangle] +pub extern "thiscall-unwind" fn rust_item_that_can_unwind() { +} + +// Now, make some assertions that the LLVM attributes for these functions are correct. First, make +// sure that the first item is correctly marked with the `nounwind` attribute: +// +// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} } +// +// Next, let's assert that the second item, which CAN unwind, does not have this attribute. +// +// CHECK: attributes #1 = { +// CHECK-NOT: nounwind +// CHECK: } From 0fd2fd92dcc0c255bb5945331b82022171ae4fa5 Mon Sep 17 00:00:00 2001 From: "katelyn a. martin" Date: Fri, 11 Dec 2020 20:54:47 -0500 Subject: [PATCH 66/67] add integration tests, unwind across FFI boundary ### Integration Tests This commit introduces some new fixtures to the `run-make-fulldeps` test suite. * c-unwind-abi-catch-panic: Exercise unwinding a panic. This catches a panic across an FFI boundary and downcasts it into an integer. * c-unwind-abi-catch-lib-panic: This is similar to the previous `*catch-panic` test, however in this case the Rust code that panics resides in a separate crate. ### Add `rust_eh_personality` to `#[no_std]` alloc tests This commit addresses some test failures that now occur in the following two tests: * no_std-alloc-error-handler-custom.rs * no_std-alloc-error-handler-default.rs Each test now defines a `rust_eh_personality` extern function, in the same manner as shown in the "Writing an executable without stdlib" section of the `lang_items` documentation here: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib Without this change, these tests would fail to compile due to a linking error explaining that there was an "undefined reference to `rust_eh_personality'." ### Updated hash * update 32-bit hash in `impl1` test ### Panics This commit uses `panic!` macro invocations that return a string, rather than using an integer as a panic payload. Doing so avoids the following warnings that were observed during rollup for the `*-msvc-1` targets: ``` warning: panic message is not a string literal --> panic.rs:10:16 | 10 | panic!(x); // That is too big! | ^ | = note: `#[warn(non_fmt_panic)]` on by default = note: this is no longer accepted in Rust 2021 help: add a "{}" format string to Display the message | 10 | panic!("{}", x); // That is too big! | ^^^^^ help: or use std::panic::panic_any instead | 10 | std::panic::panic_any(x); // That is too big! | ^^^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted ``` See: https://github.com/rust-lang-ci/rust/runs/1992118428 As these errors imply, panicking without a format string will be disallowed in Rust 2021, per #78500. --- .../c-unwind-abi-catch-lib-panic/Makefile | 30 +++++++++++++ .../c-unwind-abi-catch-lib-panic/add.c | 12 +++++ .../c-unwind-abi-catch-lib-panic/main.rs | 35 +++++++++++++++ .../c-unwind-abi-catch-lib-panic/panic.rs | 12 +++++ .../c-unwind-abi-catch-panic/Makefile | 5 +++ .../c-unwind-abi-catch-panic/add.c | 12 +++++ .../c-unwind-abi-catch-panic/main.rs | 44 +++++++++++++++++++ .../no_std-alloc-error-handler-custom.rs | 9 +++- .../no_std-alloc-error-handler-default.rs | 9 +++- src/test/ui/symbol-names/impl1.rs | 6 +-- 10 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile create mode 100644 src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/add.c create mode 100644 src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs create mode 100644 src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs create mode 100644 src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile create mode 100644 src/test/run-make-fulldeps/c-unwind-abi-catch-panic/add.c create mode 100644 src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile new file mode 100644 index 0000000000000..a8515c533af57 --- /dev/null +++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile @@ -0,0 +1,30 @@ +-include ../tools.mk + +all: archive + # Compile `main.rs`, which will link into our library, and run it. + $(RUSTC) main.rs + $(call RUN,main) + +ifdef IS_MSVC +archive: add.o panic.o + # Now, create an archive using these two objects. + $(AR) crus $(TMPDIR)/add.lib $(TMPDIR)/add.o $(TMPDIR)/panic.o +else +archive: add.o panic.o + # Now, create an archive using these two objects. + $(AR) crus $(TMPDIR)/libadd.a $(TMPDIR)/add.o $(TMPDIR)/panic.o +endif + +# Compile `panic.rs` into an object file. +# +# Note that we invoke `rustc` directly, so we may emit an object rather +# than an archive. We'll do that later. +panic.o: + $(BARE_RUSTC) $(RUSTFLAGS) \ + --out-dir $(TMPDIR) \ + --emit=obj panic.rs + +# Compile `add.c` into an object file. +add.o: + $(call COMPILE_OBJ,$(TMPDIR)/add.o,add.c) + diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/add.c b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/add.c new file mode 100644 index 0000000000000..444359451f6ec --- /dev/null +++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/add.c @@ -0,0 +1,12 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif + +// An external function, defined in Rust. +extern void panic_if_greater_than_10(unsigned x); + +unsigned add_small_numbers(unsigned a, unsigned b) { + unsigned c = a + b; + panic_if_greater_than_10(c); + return c; +} diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs new file mode 100644 index 0000000000000..78a71219c7811 --- /dev/null +++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs @@ -0,0 +1,35 @@ +//! A test for calling `C-unwind` functions across foreign function boundaries. +//! +//! This test triggers a panic in a Rust library that our foreign function invokes. This shows +//! that we can unwind through the C code in that library, and catch the underlying panic. +#![feature(c_unwind)] + +use std::panic::{catch_unwind, AssertUnwindSafe}; + +fn main() { + // Call `add_small_numbers`, passing arguments that will NOT trigger a panic. + let (a, b) = (9, 1); + let c = unsafe { add_small_numbers(a, b) }; + assert_eq!(c, 10); + + // Call `add_small_numbers`, passing arguments that will trigger a panic, and catch it. + let caught_unwind = catch_unwind(AssertUnwindSafe(|| { + let (a, b) = (10, 1); + let _c = unsafe { add_small_numbers(a, b) }; + unreachable!("should have unwound instead of returned"); + })); + + // Assert that we did indeed panic, then unwrap and downcast the panic into the sum. + assert!(caught_unwind.is_err()); + let panic_obj = caught_unwind.unwrap_err(); + let msg = panic_obj.downcast_ref::().unwrap(); + assert_eq!(msg, "11"); +} + +#[link(name = "add", kind = "static")] +extern "C-unwind" { + /// An external function, defined in C. + /// + /// Returns the sum of two numbers, or panics if the sum is greater than 10. + fn add_small_numbers(a: u32, b: u32) -> u32; +} diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs new file mode 100644 index 0000000000000..a99a04d5c6f4b --- /dev/null +++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs @@ -0,0 +1,12 @@ +#![crate_type = "staticlib"] +#![feature(c_unwind)] + +/// This function will panic if `x` is greater than 10. +/// +/// This function is called by `add_small_numbers`. +#[no_mangle] +pub extern "C-unwind" fn panic_if_greater_than_10(x: u32) { + if x > 10 { + panic!("{}", x); // That is too big! + } +} diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile new file mode 100644 index 0000000000000..9553b7aeeb983 --- /dev/null +++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: $(call NATIVE_STATICLIB,add) + $(RUSTC) main.rs + $(call RUN,main) || exit 1 diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/add.c b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/add.c new file mode 100644 index 0000000000000..444359451f6ec --- /dev/null +++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/add.c @@ -0,0 +1,12 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif + +// An external function, defined in Rust. +extern void panic_if_greater_than_10(unsigned x); + +unsigned add_small_numbers(unsigned a, unsigned b) { + unsigned c = a + b; + panic_if_greater_than_10(c); + return c; +} diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs new file mode 100644 index 0000000000000..15d38d7216058 --- /dev/null +++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs @@ -0,0 +1,44 @@ +//! A test for calling `C-unwind` functions across foreign function boundaries. +//! +//! This test triggers a panic when calling a foreign function that calls *back* into Rust. +#![feature(c_unwind)] + +use std::panic::{catch_unwind, AssertUnwindSafe}; + +fn main() { + // Call `add_small_numbers`, passing arguments that will NOT trigger a panic. + let (a, b) = (9, 1); + let c = unsafe { add_small_numbers(a, b) }; + assert_eq!(c, 10); + + // Call `add_small_numbers`, passing arguments that will trigger a panic, and catch it. + let caught_unwind = catch_unwind(AssertUnwindSafe(|| { + let (a, b) = (10, 1); + let _c = unsafe { add_small_numbers(a, b) }; + unreachable!("should have unwound instead of returned"); + })); + + // Assert that we did indeed panic, then unwrap and downcast the panic into the sum. + assert!(caught_unwind.is_err()); + let panic_obj = caught_unwind.unwrap_err(); + let msg = panic_obj.downcast_ref::().unwrap(); + assert_eq!(msg, "11"); +} + +#[link(name = "add", kind = "static")] +extern "C-unwind" { + /// An external function, defined in C. + /// + /// Returns the sum of two numbers, or panics if the sum is greater than 10. + fn add_small_numbers(a: u32, b: u32) -> u32; +} + +/// This function will panic if `x` is greater than 10. +/// +/// This function is called by `add_small_numbers`. +#[no_mangle] +pub extern "C-unwind" fn panic_if_greater_than_10(x: u32) { + if x > 10 { + panic!("{}", x); // That is too big! + } +} diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs index 4d40c7d0d2237..c9b4abbfd3fd3 100644 --- a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs +++ b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs @@ -7,7 +7,7 @@ // compile-flags:-C panic=abort // aux-build:helper.rs -#![feature(start, rustc_private, new_uninit, panic_info_message)] +#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)] #![feature(alloc_error_handler)] #![no_std] @@ -84,6 +84,13 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! { } } +// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed. +// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions +// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't +// unwind. So, for this test case we will define the symbol. +#[lang = "eh_personality"] +extern fn rust_eh_personality() {} + #[derive(Debug)] struct Page([[u64; 32]; 16]); diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs index 4f8c44f1763c8..d6cd4a6af855f 100644 --- a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs +++ b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs @@ -8,7 +8,7 @@ // aux-build:helper.rs // gate-test-default_alloc_error_handler -#![feature(start, rustc_private, new_uninit, panic_info_message)] +#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)] #![feature(default_alloc_error_handler)] #![no_std] @@ -71,6 +71,13 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! { } } +// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed. +// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions +// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't +// unwind. So, for this test case we will define the symbol. +#[lang = "eh_personality"] +extern fn rust_eh_personality() {} + #[derive(Debug)] struct Page([[u64; 32]; 16]); diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 7dd74bd229d3f..a352d255c782d 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -3,7 +3,7 @@ // revisions: legacy v0 //[legacy]compile-flags: -Z symbol-mangling-version=legacy //[v0]compile-flags: -Z symbol-mangling-version=v0 -//[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-32bit: "h13cfe136e83a9196" -> "SYMBOL_HASH" //[legacy]normalize-stderr-64bit: "hd949d7797008991f" -> "SYMBOL_HASH" #![feature(auto_traits, rustc_attrs)] @@ -75,7 +75,3 @@ fn main() { } }; } - -// FIXME(katie): The 32-bit symbol hash probably needs updating as well, but I'm slightly unsure -// about how to do that. This comment is here so that we don't break the test due to error messages -// including incorrect line numbers. From d8bfdc8ec4cc3b1aab0fed675bafa6d65aab1672 Mon Sep 17 00:00:00 2001 From: "katelyn a. martin" Date: Fri, 23 Oct 2020 18:49:34 -0400 Subject: [PATCH 67/67] address pr review comments ### Add debug assertion to check `AbiDatas` ordering This makes a small alteration to `Abi::index`, so that we include a debug assertion to check that the index we are returning corresponds with the same abi in our data array. This will help prevent ordering bugs in the future, which can manifest in rather strange errors. ### Using exhaustive ABI matches This slightly modifies the changes from our previous commits, favoring exhaustive matches in place of `_ => ...` fall-through arms. This should help with maintenance in the future, when additional ABI's are added, or when existing ABI's are modified. ### List all `-unwind` ABI's in unstable book This updates the `c-unwind` page in the unstable book to list _all_ of the other ABI strings that are introduced by this feature gate. Now, all of the ABI's specified by RFC 2945 are shown. Co-authored-by: Amanieu d'Antras Co-authored-by: Niko Matsakis --- compiler/rustc_middle/src/ty/layout.rs | 20 ++++++++++++++++++- compiler/rustc_mir_build/src/build/mod.rs | 18 ++++++++++++++++- compiler/rustc_target/src/spec/abi.rs | 15 ++++++++++++-- .../src/language-features/c-unwind.md | 3 ++- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index ee2dffd8baeb9..814581a6cf171 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2595,7 +2595,25 @@ fn fn_can_unwind( C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => { unwind } - _ => false, + Cdecl + | Fastcall + | Vectorcall + | Aapcs + | Win64 + | SysV64 + | PtxKernel + | Msp430Interrupt + | X86Interrupt + | AmdGpuKernel + | EfiApi + | AvrInterrupt + | AvrNonBlockingInterrupt + | CCmseNonSecureCall + | RustIntrinsic + | PlatformIntrinsic + | Unadjusted => false, + // In the `if` above, we checked for functions with the Rust calling convention. + Rust | RustCall => unreachable!(), } } } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index dec26278290d9..08a23d207015c 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -573,7 +573,23 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, abi: Abi) -> bo // Rust and `rust-call` functions are allowed to unwind, and should not abort. Rust | RustCall => false, // Other ABI's should abort. - _ => true, + Cdecl + | Fastcall + | Vectorcall + | Aapcs + | Win64 + | SysV64 + | PtxKernel + | Msp430Interrupt + | X86Interrupt + | AmdGpuKernel + | EfiApi + | AvrInterrupt + | AvrNonBlockingInterrupt + | CCmseNonSecureCall + | RustIntrinsic + | PlatformIntrinsic + | Unadjusted => true, } } } diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index f7f9c30d3b7a6..17eb33b8f2eaa 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -107,7 +107,7 @@ impl Abi { // N.B., this ordering MUST match the AbiDatas array above. // (This is ensured by the test indices_are_correct().) use Abi::*; - match self { + let i = match self { // Cross-platform ABIs Rust => 0, C { unwind: false } => 1, @@ -138,7 +138,18 @@ impl Abi { RustCall => 24, PlatformIntrinsic => 25, Unadjusted => 26, - } + }; + debug_assert!( + AbiDatas + .iter() + .enumerate() + .find(|(_, AbiData { abi, .. })| *abi == self) + .map(|(index, _)| index) + .expect("abi variant has associated data") + == i, + "Abi index did not match `AbiDatas` ordering" + ); + i } #[inline] diff --git a/src/doc/unstable-book/src/language-features/c-unwind.md b/src/doc/unstable-book/src/language-features/c-unwind.md index c1705d59acc21..2801d9b5e7778 100644 --- a/src/doc/unstable-book/src/language-features/c-unwind.md +++ b/src/doc/unstable-book/src/language-features/c-unwind.md @@ -6,7 +6,8 @@ The tracking issue for this feature is: [#74990] ------------------------ -Introduces a new ABI string, "C-unwind", to enable unwinding from other +Introduces four new ABI strings: "C-unwind", "stdcall-unwind", +"thiscall-unwind", and "system-unwind". These enable unwinding from other languages (such as C++) into Rust frames and from Rust into other languages. See [RFC 2945] for more information.