Skip to content

Commit 9026066

Browse files
committed
Allow #![doc(test(attr(..)))] at module level too
1 parent 6e23095 commit 9026066

File tree

7 files changed

+97
-20
lines changed

7 files changed

+97
-20
lines changed

compiler/rustc_passes/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ passes_attr_crate_level =
4646
.suggestion = to apply to the crate, use an inner attribute
4747
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
4848
49+
passes_attr_mod_level =
50+
this attribute can only be applied at module level
51+
.suggestion = to apply to the crate, use an inner attribute
52+
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-module-level> for more information
53+
4954
passes_attr_only_in_functions =
5055
`{$attr}` attribute can only be used on functions
5156

compiler/rustc_passes/src/check_attr.rs

+43-8
Original file line numberDiff line numberDiff line change
@@ -1248,7 +1248,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
12481248
let bang_span = attr.span().lo() + BytePos(1);
12491249
let sugg = (attr.style() == AttrStyle::Outer
12501250
&& self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID)
1251-
.then_some(errors::AttrCrateLevelOnlySugg {
1251+
.then_some(errors::AttrCrateLevelSugg {
12521252
attr: attr.span().with_lo(bang_span).with_hi(bang_span),
12531253
});
12541254
self.tcx.emit_node_span_lint(
@@ -1262,13 +1262,50 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
12621262
true
12631263
}
12641264

1265-
/// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if
1266-
/// valid.
1267-
fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) {
1265+
/// Checks that an attribute is used at module level. Returns `true` if valid.
1266+
fn check_attr_mod_level(
1267+
&self,
1268+
attr: &Attribute,
1269+
meta: &MetaItemInner,
1270+
hir_id: HirId,
1271+
target: Target,
1272+
) -> bool {
1273+
if target != Target::Mod {
1274+
// insert a bang between `#` and `[...`
1275+
let bang_span = attr.span().lo() + BytePos(1);
1276+
let sugg = (attr.style() == AttrStyle::Outer
1277+
&& self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID)
1278+
.then_some(errors::AttrCrateLevelSugg {
1279+
attr: attr.span().with_lo(bang_span).with_hi(bang_span),
1280+
});
1281+
self.tcx.emit_node_span_lint(
1282+
INVALID_DOC_ATTRIBUTES,
1283+
hir_id,
1284+
meta.span(),
1285+
errors::AttrModLevelOnly { sugg },
1286+
);
1287+
return false;
1288+
}
1289+
true
1290+
}
1291+
1292+
/// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place.
1293+
fn check_test_attr(
1294+
&self,
1295+
attr: &Attribute,
1296+
meta: &MetaItemInner,
1297+
hir_id: HirId,
1298+
target: Target,
1299+
) {
12681300
if let Some(metas) = meta.meta_item_list() {
12691301
for i_meta in metas {
12701302
match (i_meta.name(), i_meta.meta_item()) {
1271-
(Some(sym::attr | sym::no_crate_inject), _) => {}
1303+
(Some(sym::attr), _) => {
1304+
self.check_attr_mod_level(attr, meta, hir_id, target);
1305+
}
1306+
(Some(sym::no_crate_inject), _) => {
1307+
self.check_attr_crate_level(attr, meta, hir_id);
1308+
}
12721309
(_, Some(m)) => {
12731310
self.tcx.emit_node_span_lint(
12741311
INVALID_DOC_ATTRIBUTES,
@@ -1355,9 +1392,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
13551392
}
13561393

13571394
Some(sym::test) => {
1358-
if self.check_attr_crate_level(attr, meta, hir_id) {
1359-
self.check_test_attr(meta, hir_id);
1360-
}
1395+
self.check_test_attr(attr, meta, hir_id, target);
13611396
}
13621397

13631398
Some(

compiler/rustc_passes/src/errors.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1883,12 +1883,20 @@ pub(crate) struct UnusedVarTryIgnoreSugg {
18831883
#[note]
18841884
pub(crate) struct AttrCrateLevelOnly {
18851885
#[subdiagnostic]
1886-
pub sugg: Option<AttrCrateLevelOnlySugg>,
1886+
pub sugg: Option<AttrCrateLevelSugg>,
1887+
}
1888+
1889+
#[derive(LintDiagnostic)]
1890+
#[diag(passes_attr_mod_level)]
1891+
#[note]
1892+
pub(crate) struct AttrModLevelOnly {
1893+
#[subdiagnostic]
1894+
pub sugg: Option<AttrCrateLevelSugg>,
18871895
}
18881896

18891897
#[derive(Subdiagnostic)]
18901898
#[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")]
1891-
pub(crate) struct AttrCrateLevelOnlySugg {
1899+
pub(crate) struct AttrCrateLevelSugg {
18921900
#[primary_span]
18931901
pub attr: Span,
18941902
}

src/doc/rustdoc/src/write-documentation/the-doc-attribute.md

+9
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,22 @@ But if you include this:
141141

142142
it will not.
143143

144+
## At the module level
145+
146+
These forms of the `#[doc]` attribute are used on individual modules, to control how
147+
they are documented.
148+
144149
### `test(attr(...))`
145150

146151
This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For
147152
example, if you want your doctests to fail if they have dead code, you could add this:
148153

149154
```rust,no_run
150155
#![doc(test(attr(deny(dead_code))))]
156+
157+
mod my_mod {
158+
#![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module
159+
}
151160
```
152161

153162
## At the item level

tests/rustdoc-ui/lints/invalid-doc-attr.rs

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#![doc(masked)]
55
//~^ ERROR this attribute can only be applied to an `extern crate` item
66

7+
#[doc(test(attr(allow(warnings))))]
8+
//~^ ERROR can only be applied at module level
9+
//~| HELP to apply to the crate, use an inner attribute
10+
//~| SUGGESTION !
711
#[doc(test(no_crate_inject))]
812
//~^ ERROR can only be applied at the crate level
913
//~| HELP to apply to the crate, use an inner attribute

tests/rustdoc-ui/lints/invalid-doc-attr.stderr

+22-10
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
1-
error: this attribute can only be applied at the crate level
1+
error: this attribute can only be applied at module level
22
--> $DIR/invalid-doc-attr.rs:7:7
33
|
4+
LL | #[doc(test(attr(allow(warnings))))]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-module-level> for more information
8+
= note: `#[deny(invalid_doc_attributes)]` on by default
9+
help: to apply to the crate, use an inner attribute
10+
|
11+
LL | #![doc(test(attr(allow(warnings))))]
12+
| +
13+
14+
error: this attribute can only be applied at the crate level
15+
--> $DIR/invalid-doc-attr.rs:11:7
16+
|
417
LL | #[doc(test(no_crate_inject))]
518
| ^^^^^^^^^^^^^^^^^^^^^
619
|
720
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
8-
= note: `#[deny(invalid_doc_attributes)]` on by default
921
help: to apply to the crate, use an inner attribute
1022
|
1123
LL | #![doc(test(no_crate_inject))]
1224
| +
1325

1426
error: this attribute can only be applied to a `use` item
15-
--> $DIR/invalid-doc-attr.rs:11:7
27+
--> $DIR/invalid-doc-attr.rs:15:7
1628
|
1729
LL | #[doc(inline)]
1830
| ^^^^^^ only applicable on `use` items
@@ -23,15 +35,15 @@ LL | pub fn foo() {}
2335
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
2436

2537
error: this attribute can only be applied at the crate level
26-
--> $DIR/invalid-doc-attr.rs:16:12
38+
--> $DIR/invalid-doc-attr.rs:20:12
2739
|
2840
LL | #![doc(test(no_crate_inject))]
2941
| ^^^^^^^^^^^^^^^^^^^^^
3042
|
3143
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
3244

3345
error: conflicting doc inlining attributes
34-
--> $DIR/invalid-doc-attr.rs:26:7
46+
--> $DIR/invalid-doc-attr.rs:30:7
3547
|
3648
LL | #[doc(inline)]
3749
| ^^^^^^ this attribute...
@@ -41,7 +53,7 @@ LL | #[doc(no_inline)]
4153
= help: remove one of the conflicting attributes
4254

4355
error: this attribute can only be applied to an `extern crate` item
44-
--> $DIR/invalid-doc-attr.rs:32:7
56+
--> $DIR/invalid-doc-attr.rs:36:7
4557
|
4658
LL | #[doc(masked)]
4759
| ^^^^^^ only applicable on `extern crate` items
@@ -52,7 +64,7 @@ LL | pub struct Masked;
5264
= note: read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
5365

5466
error: this attribute cannot be applied to an `extern crate self` item
55-
--> $DIR/invalid-doc-attr.rs:36:7
67+
--> $DIR/invalid-doc-attr.rs:40:7
5668
|
5769
LL | #[doc(masked)]
5870
| ^^^^^^ not applicable on `extern crate self` items
@@ -69,15 +81,15 @@ LL | #![doc(masked)]
6981
= note: read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
7082

7183
error: this attribute can only be applied at the crate level
72-
--> $DIR/invalid-doc-attr.rs:19:11
84+
--> $DIR/invalid-doc-attr.rs:23:11
7385
|
7486
LL | #[doc(test(no_crate_inject))]
7587
| ^^^^^^^^^^^^^^^^^^^^^
7688
|
7789
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
7890

7991
error: this attribute can only be applied to a `use` item
80-
--> $DIR/invalid-doc-attr.rs:21:11
92+
--> $DIR/invalid-doc-attr.rs:25:11
8193
|
8294
LL | #[doc(inline)]
8395
| ^^^^^^ only applicable on `use` items
@@ -87,5 +99,5 @@ LL | pub fn baz() {}
8799
|
88100
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
89101

90-
error: aborting due to 9 previous errors
102+
error: aborting due to 10 previous errors
91103

tests/ui/rustdoc/doc-test-attr-pass.rs

+4
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@
66
#![doc(test(attr(deny(warnings))))]
77
#![doc(test())]
88

9+
mod test {
10+
#![doc(test(attr(allow(warnings))))]
11+
}
12+
913
pub fn foo() {}

0 commit comments

Comments
 (0)