Skip to content

Commit 9d157ad

Browse files
committed
Warn on unused doc(hidden) on trait impl items
1 parent 83322c5 commit 9d157ad

File tree

18 files changed

+225
-26
lines changed

18 files changed

+225
-26
lines changed

compiler/rustc_passes/src/check_attr.rs

+74-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
//! conflicts between multiple such attributes attached to the same
55
//! item.
66
7-
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
7+
use rustc_ast::tokenstream::DelimSpan;
8+
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MacArgs, MetaItemKind, NestedMetaItem};
89
use rustc_data_structures::fx::FxHashMap;
910
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
1011
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -810,6 +811,68 @@ impl CheckAttrVisitor<'_> {
810811
}
811812
}
812813

814+
/// Checks `#[doc(hidden)]` attributes. Returns `true` if valid.
815+
fn check_doc_hidden(
816+
&self,
817+
attr: &Attribute,
818+
meta_index: usize,
819+
meta: &NestedMetaItem,
820+
hir_id: HirId,
821+
target: Target,
822+
) -> bool {
823+
if let Target::AssocConst
824+
| Target::AssocTy
825+
| Target::Method(MethodKind::Trait { body: true }) = target
826+
{
827+
let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
828+
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
829+
830+
if Target::from_item(containing_item) == Target::Impl {
831+
let meta_items = attr.meta_item_list().unwrap();
832+
833+
let (span, replacement_span) = if meta_items.len() == 1 {
834+
(attr.span, attr.span)
835+
} else {
836+
let meta_span = meta.span();
837+
(
838+
meta_span,
839+
meta_span.until(match meta_items.get(meta_index + 1) {
840+
Some(next_item) => next_item.span(),
841+
None => match attr.get_normal_item().args {
842+
MacArgs::Delimited(DelimSpan { close, .. }, ..) => close,
843+
_ => unreachable!(),
844+
},
845+
}),
846+
)
847+
};
848+
849+
// FIXME: #[doc(hidden)] was previously erroneously allowed on trait impl items,
850+
// so for backward compatibility only emit a warning and do not mark it as invalid.
851+
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
852+
lint.build("`#[doc(hidden)]` is ignored on trait impl items")
853+
.warn(
854+
"this was previously accepted by the compiler but is \
855+
being phased out; it will become a hard error in \
856+
a future release!",
857+
)
858+
.note(
859+
"whether the impl item is `doc(hidden)` or not \
860+
entirely depends on the corresponding trait item",
861+
)
862+
.span_suggestion(
863+
replacement_span,
864+
"remove this attribute",
865+
String::new(),
866+
Applicability::MachineApplicable,
867+
)
868+
.emit();
869+
});
870+
}
871+
}
872+
873+
true
874+
}
875+
813876
/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
814877
fn check_attr_not_crate_level(
815878
&self,
@@ -928,7 +991,7 @@ impl CheckAttrVisitor<'_> {
928991
let mut is_valid = true;
929992

930993
if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() {
931-
for meta in list {
994+
for (meta_index, meta) in list.into_iter().enumerate() {
932995
if let Some(i_meta) = meta.meta_item() {
933996
match i_meta.name_or_empty() {
934997
sym::alias
@@ -969,6 +1032,15 @@ impl CheckAttrVisitor<'_> {
9691032
is_valid = false;
9701033
}
9711034

1035+
sym::hidden if !self.check_doc_hidden(attr,
1036+
meta_index,
1037+
meta,
1038+
hir_id,
1039+
target,
1040+
) => {
1041+
is_valid = false;
1042+
}
1043+
9721044
// no_default_passes: deprecated
9731045
// passes: deprecated
9741046
// plugins: removed, but rustdoc warns about it itself

library/alloc/src/collections/vec_deque/iter.rs

-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ impl<'a, T> Iterator for Iter<'a, T> {
122122
}
123123

124124
#[inline]
125-
#[doc(hidden)]
126125
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
127126
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
128127
// that is in bounds.

library/alloc/src/collections/vec_deque/iter_mut.rs

-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ impl<'a, T> Iterator for IterMut<'a, T> {
100100
}
101101

102102
#[inline]
103-
#[doc(hidden)]
104103
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
105104
// Safety: The TrustedRandomAccess contract requires that callers only pass an index
106105
// that is in bounds.

library/alloc/src/vec/into_iter.rs

-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
202202
self.len()
203203
}
204204

205-
#[doc(hidden)]
206205
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
207206
where
208207
Self: TrustedRandomAccessNoCoerce,

library/core/src/convert/num.rs

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ macro_rules! impl_float_to_int {
2525
$(
2626
#[unstable(feature = "convert_float_to_int", issue = "67057")]
2727
impl FloatToInt<$Int> for $Float {
28-
#[doc(hidden)]
2928
#[inline]
3029
unsafe fn to_int_unchecked(self) -> $Int {
3130
// SAFETY: the safety contract must be upheld by the caller.

library/core/src/iter/adapters/cloned.rs

-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ where
6060
self.it.map(T::clone).fold(init, f)
6161
}
6262

63-
#[doc(hidden)]
6463
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
6564
where
6665
Self: TrustedRandomAccessNoCoerce,

library/core/src/iter/adapters/copied.rs

-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ where
8181
self.it.advance_by(n)
8282
}
8383

84-
#[doc(hidden)]
8584
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
8685
where
8786
Self: TrustedRandomAccessNoCoerce,

library/core/src/iter/adapters/enumerate.rs

-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ where
128128
}
129129

130130
#[rustc_inherit_overflow_checks]
131-
#[doc(hidden)]
132131
#[inline]
133132
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
134133
where

library/core/src/iter/adapters/fuse.rs

-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ where
129129
}
130130

131131
#[inline]
132-
#[doc(hidden)]
133132
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
134133
where
135134
Self: TrustedRandomAccessNoCoerce,

library/core/src/iter/adapters/map.rs

-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ where
124124
self.iter.fold(init, map_fold(self.f, g))
125125
}
126126

127-
#[doc(hidden)]
128127
#[inline]
129128
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
130129
where

library/core/src/iter/adapters/zip.rs

-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ where
9595
}
9696

9797
#[inline]
98-
#[doc(hidden)]
9998
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
10099
where
101100
Self: TrustedRandomAccessNoCoerce,

library/core/src/iter/range.rs

-1
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,6 @@ impl<A: Step> Iterator for ops::Range<A> {
752752
}
753753

754754
#[inline]
755-
#[doc(hidden)]
756755
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
757756
where
758757
Self: TrustedRandomAccessNoCoerce,

library/core/src/slice/iter.rs

-11
Original file line numberDiff line numberDiff line change
@@ -1322,7 +1322,6 @@ impl<'a, T> Iterator for Windows<'a, T> {
13221322
}
13231323
}
13241324

1325-
#[doc(hidden)]
13261325
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
13271326
// SAFETY: since the caller guarantees that `i` is in bounds,
13281327
// which means that `i` cannot overflow an `isize`, and the
@@ -1478,7 +1477,6 @@ impl<'a, T> Iterator for Chunks<'a, T> {
14781477
}
14791478
}
14801479

1481-
#[doc(hidden)]
14821480
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
14831481
let start = idx * self.chunk_size;
14841482
// SAFETY: the caller guarantees that `i` is in bounds,
@@ -1657,7 +1655,6 @@ impl<'a, T> Iterator for ChunksMut<'a, T> {
16571655
}
16581656
}
16591657

1660-
#[doc(hidden)]
16611658
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
16621659
let start = idx * self.chunk_size;
16631660
// SAFETY: see comments for `Chunks::__iterator_get_unchecked`.
@@ -1830,7 +1827,6 @@ impl<'a, T> Iterator for ChunksExact<'a, T> {
18301827
self.next_back()
18311828
}
18321829

1833-
#[doc(hidden)]
18341830
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
18351831
let start = idx * self.chunk_size;
18361832
// SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`.
@@ -1984,7 +1980,6 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> {
19841980
self.next_back()
19851981
}
19861982

1987-
#[doc(hidden)]
19881983
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
19891984
let start = idx * self.chunk_size;
19901985
// SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`.
@@ -2248,7 +2243,6 @@ impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
22482243
self.iter.last()
22492244
}
22502245

2251-
#[doc(hidden)]
22522246
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] {
22532247
// SAFETY: The safety guarantees of `__iterator_get_unchecked` are
22542248
// transferred to the caller.
@@ -2367,7 +2361,6 @@ impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
23672361
self.iter.last()
23682362
}
23692363

2370-
#[doc(hidden)]
23712364
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
23722365
// SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to
23732366
// the caller.
@@ -2520,7 +2513,6 @@ impl<'a, T> Iterator for RChunks<'a, T> {
25202513
}
25212514
}
25222515

2523-
#[doc(hidden)]
25242516
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
25252517
let end = self.v.len() - idx * self.chunk_size;
25262518
let start = match end.checked_sub(self.chunk_size) {
@@ -2689,7 +2681,6 @@ impl<'a, T> Iterator for RChunksMut<'a, T> {
26892681
}
26902682
}
26912683

2692-
#[doc(hidden)]
26932684
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
26942685
let end = self.v.len() - idx * self.chunk_size;
26952686
let start = match end.checked_sub(self.chunk_size) {
@@ -2856,7 +2847,6 @@ impl<'a, T> Iterator for RChunksExact<'a, T> {
28562847
self.next_back()
28572848
}
28582849

2859-
#[doc(hidden)]
28602850
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
28612851
let end = self.v.len() - idx * self.chunk_size;
28622852
let start = end - self.chunk_size;
@@ -3016,7 +3006,6 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> {
30163006
self.next_back()
30173007
}
30183008

3019-
#[doc(hidden)]
30203009
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
30213010
let end = self.v.len() - idx * self.chunk_size;
30223011
let start = end - self.chunk_size;

library/core/src/slice/iter/macros.rs

-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,6 @@ macro_rules! iterator {
325325
None
326326
}
327327

328-
#[doc(hidden)]
329328
#[inline]
330329
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
331330
// SAFETY: the caller must guarantee that `i` is in bounds of

library/core/src/str/iter.rs

-1
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,6 @@ impl Iterator for Bytes<'_> {
298298
}
299299

300300
#[inline]
301-
#[doc(hidden)]
302301
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 {
303302
// SAFETY: the caller must uphold the safety contract
304303
// for `Iterator::__iterator_get_unchecked`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![deny(unused_attributes)]
2+
#![crate_type = "lib"]
3+
// run-rustfix
4+
5+
pub trait Trait {
6+
type It;
7+
const IT: ();
8+
fn it0();
9+
fn it1();
10+
fn it2();
11+
}
12+
13+
pub struct Implementor;
14+
15+
impl Trait for Implementor {
16+
17+
type It = ();
18+
//~^^ ERROR `#[doc(hidden)]` is ignored
19+
//~| WARNING this was previously accepted
20+
21+
22+
const IT: () = ();
23+
//~^^ ERROR `#[doc(hidden)]` is ignored
24+
//~| WARNING this was previously accepted
25+
26+
#[doc(alias = "aka")]
27+
fn it0() {}
28+
//~^^ ERROR `#[doc(hidden)]` is ignored
29+
//~| WARNING this was previously accepted
30+
31+
#[doc(alias = "this", )]
32+
fn it1() {}
33+
//~^^ ERROR `#[doc(hidden)]` is ignored
34+
//~| WARNING this was previously accepted
35+
36+
#[doc()]
37+
fn it2() {}
38+
//~^^ ERROR `#[doc(hidden)]` is ignored
39+
//~| WARNING this was previously accepted
40+
//~| ERROR `#[doc(hidden)]` is ignored
41+
//~| WARNING this was previously accepted
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![deny(unused_attributes)]
2+
#![crate_type = "lib"]
3+
// run-rustfix
4+
5+
pub trait Trait {
6+
type It;
7+
const IT: ();
8+
fn it0();
9+
fn it1();
10+
fn it2();
11+
}
12+
13+
pub struct Implementor;
14+
15+
impl Trait for Implementor {
16+
#[doc(hidden)]
17+
type It = ();
18+
//~^^ ERROR `#[doc(hidden)]` is ignored
19+
//~| WARNING this was previously accepted
20+
21+
#[doc(hidden)]
22+
const IT: () = ();
23+
//~^^ ERROR `#[doc(hidden)]` is ignored
24+
//~| WARNING this was previously accepted
25+
26+
#[doc(hidden, alias = "aka")]
27+
fn it0() {}
28+
//~^^ ERROR `#[doc(hidden)]` is ignored
29+
//~| WARNING this was previously accepted
30+
31+
#[doc(alias = "this", hidden,)]
32+
fn it1() {}
33+
//~^^ ERROR `#[doc(hidden)]` is ignored
34+
//~| WARNING this was previously accepted
35+
36+
#[doc(hidden, hidden)]
37+
fn it2() {}
38+
//~^^ ERROR `#[doc(hidden)]` is ignored
39+
//~| WARNING this was previously accepted
40+
//~| ERROR `#[doc(hidden)]` is ignored
41+
//~| WARNING this was previously accepted
42+
}

0 commit comments

Comments
 (0)