diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 7dc5c6ce9f2b8..c7335c1aab171 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -14,8 +14,8 @@ use super::prelude::{ALL_TARGETS, AllowedTargets}; use super::{AcceptMapping, AttributeParser, template}; use crate::context::{AcceptContext, FinalizeContext}; use crate::diagnostics::{ - AttrCrateLevelOnly, DocAliasBadChar, DocAliasDuplicated, DocAliasEmpty, DocAliasMalformed, - DocAliasStartEnd, DocAttrNotCrateLevel, DocAttributeNotAttribute, DocAutoCfgExpectsHideOrShow, + DocAliasBadChar, DocAliasDuplicated, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, + DocAttrNotCrateLevel, DocAttributeNotAttribute, DocAutoCfgExpectsHideOrShow, DocAutoCfgHideShowExpectsList, DocAutoCfgHideShowNoIdentBeforeValues, DocAutoCfgHideShowUnexpectedItem, DocAutoCfgHideShowUnexpectedItemAfterValues, DocAutoCfgHideShowValuesMix, DocAutoCfgWrongLiteral, DocInlineConflict, DocInlineOnlyUse, @@ -26,6 +26,7 @@ use crate::diagnostics::{ use crate::parser::{ ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser, }; +use crate::target_checking::Policy::Allow; fn check_keyword(cx: &mut AcceptContext<'_, '_>, keyword: Symbol, span: Span) -> bool { // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we @@ -63,15 +64,6 @@ fn check_attr_not_crate_level( true } -/// Checks that an attribute is used at the crate level. Returns `true` if valid. -fn check_attr_crate_level(cx: &mut AcceptContext<'_, '_>, span: Span) -> bool { - if cx.shared.target != Target::Crate { - cx.emit_lint(INVALID_DOC_ATTRIBUTES, AttrCrateLevelOnly, span); - return false; - } - true -} - // FIXME: To be removed once merged and replace with `cx.expected_name_value(span, _name)`. fn expected_name_value(cx: &mut AcceptContext<'_, '_>, span: Span, _name: Option) { cx.emit_lint(INVALID_DOC_ATTRIBUTES, ExpectedNameValue, span); @@ -163,9 +155,10 @@ impl DocParser { return; } - if !check_attr_crate_level(cx, path.span()) { - return; - } + cx.check_target( + sym::no_crate_inject.as_str(), + &AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]), + ); self.attribute.no_crate_inject = Some(path.span()) } @@ -552,9 +545,10 @@ impl DocParser { return; } let span = path.span(); - if !check_attr_crate_level(cx, span) { - return; - } + cx.check_target( + concat!("(", stringify!($ident), ")"), + &AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]), + ); self.attribute.$ident = Some(span); }}; } @@ -570,9 +564,10 @@ impl DocParser { return; }; - if !check_attr_crate_level(cx, path.span()) { - return; - } + cx.check_target( + s.as_str(), + &AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]), + ); // FIXME: It's errorring when the attribute is passed multiple times on the command // line. diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index b5bfbc9e3dc3b..2b41db75ed5bb 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -320,13 +320,6 @@ pub(crate) struct DocTestUnknown { #[diag("`#![doc(test(...)]` does not take a literal")] pub(crate) struct DocTestLiteral; -#[derive(Diagnostic)] -#[diag("this attribute can only be applied at the crate level")] -#[note( - "read for more information" -)] -pub(crate) struct AttrCrateLevelOnly; - #[derive(Diagnostic)] #[diag("conflicting doc inlining attributes")] #[help("remove one of the conflicting attributes")] @@ -347,6 +340,13 @@ pub(crate) struct DocInlineOnlyUse { pub item_span: Span, } +#[derive(Diagnostic)] +#[diag("this attribute can only be applied at the crate level")] +#[note( + "read for more information" +)] +pub(crate) struct AttrCrateLevelOnly; + #[derive(Diagnostic)] #[diag("`#[diagnostic::do_not_recommend]` does not expect any arguments")] pub(crate) struct DoNotRecommendDoesNotExpectArgs; diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 7eb3e8e1f319a..723f4a31823ab 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -6,7 +6,7 @@ use rustc_attr_ir::{AttrItem, Attribute, AttributeKind}; use rustc_errors::{DiagArgValue, MultiSpan, StashKey}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ - MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, USELESS_DEPRECATED, + INVALID_DOC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, USELESS_DEPRECATED, }; use rustc_span::{BytePos, FileName, RemapPathScopeComponents, Span, Symbol, sym}; @@ -244,6 +244,16 @@ impl<'sess> AttributeParser<'sess> { }) .unwrap_or_default(); + if name == "doc" { + let diag = crate::diagnostics::AttrCrateLevelOnly; + if warn { + cx.emit_lint(INVALID_DOC_ATTRIBUTES, diag, attr_span); + } else { + cx.emit_err(diag); + } + return; + } + let diag = crate::diagnostics::InvalidAttrStyle { name, is_used_as_inner, diff --git a/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs b/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs index afb0a5987deb3..e38a63cd12550 100644 --- a/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs +++ b/tests/rustdoc-ui/lints/invalid-crate-level-lint.rs @@ -6,7 +6,8 @@ pub mod bar { #![doc(test(no_crate_inject))] - //~^ ERROR can only be applied at the crate level + //~^ ERROR unused attribute + //~| WARN this was previously accepted by the compiler but is being phased out #[doc(test(no_crate_inject))] //~^ ERROR can only be applied at the crate level diff --git a/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr b/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr index 7569cf575e510..b98b6fda035f4 100644 --- a/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr +++ b/tests/rustdoc-ui/lints/invalid-crate-level-lint.stderr @@ -1,8 +1,8 @@ error: this attribute can only be applied at the crate level - --> $DIR/invalid-crate-level-lint.rs:4:12 + --> $DIR/invalid-crate-level-lint.rs:4:1 | LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information note: the lint level is defined here @@ -11,19 +11,24 @@ note: the lint level is defined here LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: this attribute can only be applied at the crate level +error: unused attribute --> $DIR/invalid-crate-level-lint.rs:8:17 | LL | #![doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: remove this attribute | - = note: read for more information +note: attribute also specified here + --> $DIR/invalid-crate-level-lint.rs:4:12 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! error: this attribute can only be applied at the crate level - --> $DIR/invalid-crate-level-lint.rs:11:16 + --> $DIR/invalid-crate-level-lint.rs:12:5 | LL | #[doc(test(no_crate_inject))] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: read for more information diff --git a/tests/ui/attributes/doc-crate-level.rs b/tests/ui/attributes/doc-crate-level.rs new file mode 100644 index 0000000000000..c58866022e2c2 --- /dev/null +++ b/tests/ui/attributes/doc-crate-level.rs @@ -0,0 +1,22 @@ +//@check-pass +#![feature(rustdoc_internals)] + +#[doc(rust_logo)] +//~^ WARN this attribute can only be applied at the crate level +#[doc(html_favicon_url = "example.org")] +//~^ WARN this attribute can only be applied at the crate level +#[doc(html_logo_url = "example.org")] +//~^ WARN this attribute can only be applied at the crate level +#[doc(html_playground_url = "example.org")] +//~^ WARN this attribute can only be applied at the crate level +#[doc(issue_tracker_base_url = "example.org")] +//~^ WARN this attribute can only be applied at the crate level +#[doc(html_root_url = "example.org")] +//~^ WARN this attribute can only be applied at the crate level +#[doc(html_no_source)] +//~^ WARN this attribute can only be applied at the crate level +#[doc(test(no_crate_inject))] +//~^ WARN this attribute can only be applied at the crate level +fn function() {} + +fn main() {} diff --git a/tests/ui/attributes/doc-crate-level.stderr b/tests/ui/attributes/doc-crate-level.stderr new file mode 100644 index 0000000000000..71c385e576101 --- /dev/null +++ b/tests/ui/attributes/doc-crate-level.stderr @@ -0,0 +1,67 @@ +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:4:1 + | +LL | #[doc(rust_logo)] + | ^^^^^^^^^^^^^^^^^ + | + = note: read for more information + = note: `#[warn(invalid_doc_attributes)]` on by default + +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:6:1 + | +LL | #[doc(html_favicon_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:8:1 + | +LL | #[doc(html_logo_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:10:1 + | +LL | #[doc(html_playground_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:12:1 + | +LL | #[doc(issue_tracker_base_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:14:1 + | +LL | #[doc(html_root_url = "example.org")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:16:1 + | +LL | #[doc(html_no_source)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + +warning: this attribute can only be applied at the crate level + --> $DIR/doc-crate-level.rs:18:1 + | +LL | #[doc(test(no_crate_inject))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: read for more information + +warning: 8 warnings emitted + diff --git a/tests/ui/feature-gates/doc-rust-logo.stderr b/tests/ui/feature-gates/doc-rust-logo.stderr index 802187e6a598c..47f7e7480bf1a 100644 --- a/tests/ui/feature-gates/doc-rust-logo.stderr +++ b/tests/ui/feature-gates/doc-rust-logo.stderr @@ -9,10 +9,10 @@ LL | #![doc(rust_logo)] = note: the `#[doc(rust_logo)]` attribute is used for Rust branding warning: this attribute can only be applied at the crate level - --> $DIR/doc-rust-logo.rs:5:7 + --> $DIR/doc-rust-logo.rs:5:1 | LL | #[doc(rust_logo)] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: read for more information = note: `#[warn(invalid_doc_attributes)]` on by default