diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 2f264ed4fc02..6d815e510ea2 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -46,11 +46,6 @@ passes_attr_crate_level = .suggestion = to apply to the crate, use an inner attribute .note = read for more information -passes_attr_mod_level = - this attribute can only be applied at module level - .suggestion = to apply to the crate, use an inner attribute at the crate level - .note = read for more information - passes_attr_only_in_functions = `{$attr}` attribute can only be used on functions diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 376b424a1af5..29063ea8d291 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1252,7 +1252,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let bang_span = attr.span().lo() + BytePos(1); let sugg = (attr.style() == AttrStyle::Outer && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelSugg { + .then_some(errors::AttrCrateLevelOnlySugg { attr: attr.span().with_lo(bang_span).with_hi(bang_span), }); self.tcx.emit_node_span_lint( @@ -1266,46 +1266,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } - /// Checks that an attribute is used at module level. Returns `true` if valid. - fn check_attr_mod_level( - &self, - attr: &Attribute, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - ) -> bool { - if target != Target::Mod { - // insert a bang between `#` and `[...` - let bang_span = attr.span().lo() + BytePos(1); - let sugg = (attr.style() == AttrStyle::Outer - && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) - .then_some(errors::AttrCrateLevelSugg { - attr: attr.span().with_lo(bang_span).with_hi(bang_span), - }); - self.tcx.emit_node_span_lint( - INVALID_DOC_ATTRIBUTES, - hir_id, - meta.span(), - errors::AttrModLevelOnly { sugg }, - ); - return false; - } - true - } - /// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place. - fn check_test_attr( - &self, - attr: &Attribute, - meta: &MetaItemInner, - hir_id: HirId, - target: Target, - ) { + fn check_test_attr(&self, attr: &Attribute, meta: &MetaItemInner, hir_id: HirId) { if let Some(metas) = meta.meta_item_list() { for i_meta in metas { match (i_meta.name(), i_meta.meta_item()) { (Some(sym::attr), _) => { - self.check_attr_mod_level(attr, meta, hir_id, target); + // Allowed everywhere like `#[doc]` } (Some(sym::no_crate_inject), _) => { self.check_attr_crate_level(attr, meta, hir_id); @@ -1396,7 +1363,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Some(sym::test) => { - self.check_test_attr(attr, meta, hir_id, target); + self.check_test_attr(attr, meta, hir_id); } Some( diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 38b0db37e12b..00682a9c7a79 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1890,20 +1890,12 @@ pub(crate) struct UnusedVarTryIgnoreSugg { #[note] pub(crate) struct AttrCrateLevelOnly { #[subdiagnostic] - pub sugg: Option, -} - -#[derive(LintDiagnostic)] -#[diag(passes_attr_mod_level)] -#[note] -pub(crate) struct AttrModLevelOnly { - #[subdiagnostic] - pub sugg: Option, + pub sugg: Option, } #[derive(Subdiagnostic)] #[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")] -pub(crate) struct AttrCrateLevelSugg { +pub(crate) struct AttrCrateLevelOnlySugg { #[primary_span] pub attr: Span, } diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index afbcf4000c53..a70861faa761 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -141,34 +141,6 @@ But if you include this: it will not. -## At the module level - -These forms of the `#[doc]` attribute are used on individual modules, to control how -they are documented. - -### `test(attr(...))` - -This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For -example, if you want your doctests to fail if they have dead code, you could add this: - -```rust,no_run -#![doc(test(attr(deny(dead_code))))] - -mod my_mod { - #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module -} -``` - -`test(attr(..))` attributes are appended to the parent module's, they do not replace the current -list of attributes. In the previous example, both attributes would be present: - -```rust,no_run -// For every doctest in `my_mod` - -#![deny(dead_code)] // from the crate-root -#![allow(dead_code)] // from `my_mod` -``` - ## At the item level These forms of the `#[doc]` attribute are used on individual items, to control how @@ -300,3 +272,26 @@ To get around this limitation, we just add `#[doc(alias = "lib_name_do_something on the `do_something` method and then it's all good! Users can now look for `lib_name_do_something` in our crate directly and find `Obj::do_something`. + +### `test(attr(...))` + +This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For +example, if you want your doctests to fail if they have dead code, you could add this: + +```rust,no_run +#![doc(test(attr(deny(dead_code))))] + +mod my_mod { + #![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module +} +``` + +`test(attr(..))` attributes are appended to the parent module's, they do not replace the current +list of attributes. In the previous example, both attributes would be present: + +```rust,no_run +// For every doctest in `my_mod` + +#![deny(dead_code)] // from the crate-root +#![allow(dead_code)] // from `my_mod` +``` diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.rs b/tests/rustdoc-ui/lints/invalid-doc-attr.rs index cd5ae44b1266..e1cc08ca2427 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.rs +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.rs @@ -4,10 +4,6 @@ #![doc(masked)] //~^ ERROR this attribute can only be applied to an `extern crate` item -#[doc(test(attr(allow(warnings))))] -//~^ ERROR can only be applied at module level -//~| HELP to apply to the crate, use an inner attribute -//~| SUGGESTION ! #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level //~| HELP to apply to the crate, use an inner attribute diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr index 0fd55ff94d87..7621999a8ca5 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr.stderr @@ -1,30 +1,18 @@ -error: this attribute can only be applied at module level - --> $DIR/invalid-doc-attr.rs:7:7 - | -LL | #[doc(test(attr(allow(warnings))))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: read for more information - = note: `#[deny(invalid_doc_attributes)]` on by default -help: to apply to the crate, use an inner attribute at the crate level - | -LL | #![doc(test(attr(allow(warnings))))] - | + - error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:11:7 + --> $DIR/invalid-doc-attr.rs:7:7 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information + = note: `#[deny(invalid_doc_attributes)]` on by default help: to apply to the crate, use an inner attribute | LL | #![doc(test(no_crate_inject))] | + error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:15:7 + --> $DIR/invalid-doc-attr.rs:11:7 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -35,7 +23,7 @@ LL | pub fn foo() {} = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:20:12 + --> $DIR/invalid-doc-attr.rs:16:12 | LL | #![doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +31,7 @@ LL | #![doc(test(no_crate_inject))] = note: read for more information error: conflicting doc inlining attributes - --> $DIR/invalid-doc-attr.rs:30:7 + --> $DIR/invalid-doc-attr.rs:26:7 | LL | #[doc(inline)] | ^^^^^^ this attribute... @@ -53,7 +41,7 @@ LL | #[doc(no_inline)] = help: remove one of the conflicting attributes error: this attribute can only be applied to an `extern crate` item - --> $DIR/invalid-doc-attr.rs:36:7 + --> $DIR/invalid-doc-attr.rs:32:7 | LL | #[doc(masked)] | ^^^^^^ only applicable on `extern crate` items @@ -64,7 +52,7 @@ LL | pub struct Masked; = note: read for more information error: this attribute cannot be applied to an `extern crate self` item - --> $DIR/invalid-doc-attr.rs:40:7 + --> $DIR/invalid-doc-attr.rs:36:7 | LL | #[doc(masked)] | ^^^^^^ not applicable on `extern crate self` items @@ -81,7 +69,7 @@ LL | #![doc(masked)] = note: read for more information error: this attribute can only be applied at the crate level - --> $DIR/invalid-doc-attr.rs:23:11 + --> $DIR/invalid-doc-attr.rs:19:11 | LL | #[doc(test(no_crate_inject))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +77,7 @@ LL | #[doc(test(no_crate_inject))] = note: read for more information error: this attribute can only be applied to a `use` item - --> $DIR/invalid-doc-attr.rs:25:11 + --> $DIR/invalid-doc-attr.rs:21:11 | LL | #[doc(inline)] | ^^^^^^ only applicable on `use` items @@ -99,5 +87,5 @@ LL | pub fn baz() {} | = note: read for more information -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/lint/unused/useless-comment.rs b/tests/ui/lint/unused/useless-comment.rs index 4ec52f20747d..898665278e39 100644 --- a/tests/ui/lint/unused/useless-comment.rs +++ b/tests/ui/lint/unused/useless-comment.rs @@ -9,8 +9,13 @@ macro_rules! mac { /// foo //~ ERROR unused doc comment mac!(); +/// a //~ ERROR unused doc comment +#[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment +unsafe extern "C" { } + fn foo() { /// a //~ ERROR unused doc comment + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment let x = 12; /// multi-line //~ ERROR unused doc comment @@ -19,6 +24,7 @@ fn foo() { match x { /// c //~ ERROR unused doc comment 1 => {}, + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment _ => {} } @@ -32,6 +38,7 @@ fn foo() { /// bar //~ ERROR unused doc comment mac!(); + #[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment let x = /** comment */ 47; //~ ERROR unused doc comment /// dox //~ ERROR unused doc comment diff --git a/tests/ui/lint/unused/useless-comment.stderr b/tests/ui/lint/unused/useless-comment.stderr index 8bb5bdaeb250..39873b82b757 100644 --- a/tests/ui/lint/unused/useless-comment.stderr +++ b/tests/ui/lint/unused/useless-comment.stderr @@ -12,7 +12,28 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ error: unused doc comment - --> $DIR/useless-comment.rs:32:5 + --> $DIR/useless-comment.rs:12:1 + | +LL | /// a + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(test(attr(allow(dead_code))))] +LL | unsafe extern "C" { } + | --------------------- rustdoc does not generate documentation for extern blocks + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:13:1 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe extern "C" { } + | --------------------- rustdoc does not generate documentation for extern blocks + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:38:5 | LL | /// bar | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations @@ -20,17 +41,28 @@ LL | /// bar = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion error: unused doc comment - --> $DIR/useless-comment.rs:13:5 + --> $DIR/useless-comment.rs:17:5 | LL | /// a | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(test(attr(allow(dead_code))))] LL | let x = 12; | ----------- rustdoc does not generate documentation for statements | = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:16:5 + --> $DIR/useless-comment.rs:18:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = 12; + | ----------- rustdoc does not generate documentation for statements + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:21:5 | LL | / /// multi-line LL | | /// doc comment @@ -39,6 +71,7 @@ LL | | /// that is unused LL | / match x { LL | | /// c LL | | 1 => {}, +LL | | #[doc(test(attr(allow(dead_code))))] LL | | _ => {} LL | | } | |_____- rustdoc does not generate documentation for expressions @@ -46,7 +79,7 @@ LL | | } = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:20:9 + --> $DIR/useless-comment.rs:25:9 | LL | /// c | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +89,17 @@ LL | 1 => {}, = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:25:5 + --> $DIR/useless-comment.rs:27:9 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | _ => {} + | ------- rustdoc does not generate documentation for match arms + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:31:5 | LL | /// foo | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +109,7 @@ LL | unsafe {} = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:28:5 + --> $DIR/useless-comment.rs:34:5 | LL | #[doc = "foo"] | ^^^^^^^^^^^^^^ @@ -77,7 +120,7 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:29:5 + --> $DIR/useless-comment.rs:35:5 | LL | #[doc = "bar"] | ^^^^^^^^^^^^^^ @@ -87,7 +130,17 @@ LL | 3; = help: use `//` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:35:13 + --> $DIR/useless-comment.rs:41:5 + | +LL | #[doc(test(attr(allow(dead_code))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let x = /** comment */ 47; + | -------------------------- rustdoc does not generate documentation for statements + | + = help: use `//` for a plain comment + +error: unused doc comment + --> $DIR/useless-comment.rs:42:13 | LL | let x = /** comment */ 47; | ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions @@ -95,7 +148,7 @@ LL | let x = /** comment */ 47; = help: use `/* */` for a plain comment error: unused doc comment - --> $DIR/useless-comment.rs:37:5 + --> $DIR/useless-comment.rs:44:5 | LL | /// dox | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,5 +159,5 @@ LL | | } | = help: use `//` for a plain comment -error: aborting due to 10 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/rustdoc/doc-test-attr-pass.rs b/tests/ui/rustdoc/doc-test-attr-pass.rs index 40ffd5b25723..60d1e3722bdf 100644 --- a/tests/ui/rustdoc/doc-test-attr-pass.rs +++ b/tests/ui/rustdoc/doc-test-attr-pass.rs @@ -10,4 +10,42 @@ mod test { #![doc(test(attr(allow(warnings))))] } +#[doc(test(attr(allow(dead_code))))] +static S: u32 = 5; + +#[doc(test(attr(allow(dead_code))))] +const C: u32 = 5; + +#[doc(test(attr(deny(dead_code))))] +struct A { + #[doc(test(attr(allow(dead_code))))] + field: u32 +} + +#[doc(test(attr(deny(dead_code))))] +union U { + #[doc(test(attr(allow(dead_code))))] + field: u32, + field2: u64, +} + +#[doc(test(attr(deny(dead_code))))] +enum Enum { + #[doc(test(attr(allow(dead_code))))] + Variant1, +} + +#[doc(test(attr(deny(dead_code))))] +impl A { + #[doc(test(attr(deny(dead_code))))] + fn method() {} +} + +#[doc(test(attr(deny(dead_code))))] +trait MyTrait { + #[doc(test(attr(deny(dead_code))))] + fn my_trait_fn(); +} + +#[doc(test(attr(deny(dead_code))))] pub fn foo() {}