diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs index 1e62c03fc3b6..349b54706623 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -1,8 +1,10 @@ +use rustc_errors::Diagnostic; use rustc_hir::attrs::diagnostic::Directive; +use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; use crate::attributes::diagnostic::*; use crate::attributes::prelude::*; - +use crate::errors::DiagnosticOnConstOnlyForTraitImpls; #[derive(Default)] pub(crate) struct OnConstParser { span: Option, @@ -21,6 +23,21 @@ impl AttributeParser for OnConstParser { let span = cx.attr_span; this.span = Some(span); + + // FIXME(mejrs) no constness field on `Target`, + // so non-constness is still checked in check_attr.rs + if !matches!(cx.target, Target::Impl { of_trait: true }) { + let target_span = cx.target_span; + cx.emit_dyn_lint( + MISPLACED_DIAGNOSTIC_ATTRIBUTES, + move |dcx, level| { + DiagnosticOnConstOnlyForTraitImpls { target_span }.into_diag(dcx, level) + }, + span, + ); + return; + } + let mode = Mode::DiagnosticOnConst; let Some(items) = parse_list(cx, args, mode) else { return }; @@ -32,7 +49,8 @@ impl AttributeParser for OnConstParser { }, )]; - //FIXME Still checked in `check_attr.rs` + // "Allowed" on all targets; noop on anything but non-const trait impls; + // this linted on in parser. const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index ca57c25f25a0..cff8feb933ef 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -252,3 +252,10 @@ pub(crate) struct DocUnknownAny { #[derive(Diagnostic)] #[diag("expected boolean for `#[doc(auto_cfg = ...)]`")] pub(crate) struct DocAutoCfgWrongLiteral; + +#[derive(Diagnostic)] +#[diag("`#[diagnostic::on_const]` can only be applied to trait impls")] +pub(crate) struct DiagnosticOnConstOnlyForTraitImpls { + #[label("not a trait impl")] + pub target_span: Span, +} diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 10a805a159b0..ecc83628971c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -54,13 +54,6 @@ #[diag("`#[diagnostic::on_unimplemented]` can only be applied to trait definitions")] struct DiagnosticOnUnimplementedOnlyForTraits; -#[derive(Diagnostic)] -#[diag("`#[diagnostic::on_const]` can only be applied to trait impls")] -struct DiagnosticOnConstOnlyForTraitImpls { - #[label("not a trait impl")] - item_span: Span, -} - #[derive(Diagnostic)] #[diag("`#[diagnostic::on_const]` can only be applied to non-const trait impls")] struct DiagnosticOnConstOnlyForNonConstTraitImpls { @@ -587,7 +580,7 @@ fn check_diagnostic_on_unimplemented( } } - /// Checks if `#[diagnostic::on_const]` is applied to a trait impl + /// Checks if `#[diagnostic::on_const]` is applied to a on-const trait impl fn check_diagnostic_on_const( &self, attr_span: Span, @@ -595,6 +588,8 @@ fn check_diagnostic_on_const( target: Target, item: Option>, ) { + // We only check the non-constness here. A diagnostic for use + // on not-trait impl items is issued during attribute parsing. if target == (Target::Impl { of_trait: true }) { match item.unwrap() { ItemLike::Item(it) => match it.expect_impl().constness { @@ -613,16 +608,9 @@ fn check_diagnostic_on_const( ItemLike::ForeignItem => {} } } - let item_span = self.tcx.hir_span(hir_id); - self.tcx.emit_node_span_lint( - MISPLACED_DIAGNOSTIC_ATTRIBUTES, - hir_id, - attr_span, - DiagnosticOnConstOnlyForTraitImpls { item_span }, - ); - - // We don't check the validity of generic args here...whose generics would that be, anyway? - // The traits' or the impls'? + // FIXME(#155570) Can we do something with generic args here? + // regardless, we don't check the validity of generic args here + // ...whose generics would that be, anyway? The traits' or the impls'? } /// Checks if `#[diagnostic::on_move]` is applied to an ADT definition diff --git a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr index f92ea501696e..609bc540ef8e 100644 --- a/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr +++ b/tests/ui/diagnostic_namespace/on_const/misplaced_attr.stderr @@ -1,18 +1,3 @@ -error: `#[diagnostic::on_const]` can only be applied to trait impls - --> $DIR/misplaced_attr.rs:4:1 - | -LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | pub struct Foo; - | -------------- not a trait impl - | -note: the lint level is defined here - --> $DIR/misplaced_attr.rs:2:9 - | -LL | #![deny(misplaced_diagnostic_attributes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: `#[diagnostic::on_const]` can only be applied to non-const trait impls --> $DIR/misplaced_attr.rs:8:1 | @@ -21,24 +6,45 @@ LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] LL | LL | impl const PartialEq for Foo { | ---------------------------- this is a const trait impl + | +note: the lint level is defined here + --> $DIR/misplaced_attr.rs:2:9 + | +LL | #![deny(misplaced_diagnostic_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[diagnostic::on_const]` can only be applied to trait impls - --> $DIR/misplaced_attr.rs:16:1 + --> $DIR/misplaced_attr.rs:4:1 | LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | impl Foo { - | -------- not a trait impl +LL | pub struct Foo; + | --------------- not a trait impl + +error: `#[diagnostic::on_const]` can only be applied to trait impls + --> $DIR/misplaced_attr.rs:16:1 + | +LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / impl Foo { +LL | | fn eq(&self, _other: &Foo) -> bool { +LL | | true +LL | | } +LL | | } + | |_- not a trait impl error: `#[diagnostic::on_const]` can only be applied to trait impls --> $DIR/misplaced_attr.rs:25:5 | -LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[diagnostic::on_const(message = "tadaa", note = "boing")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | fn partial_cmp(&self, other: &Foo) -> Option { - | ---------------------------------------------------------------- not a trait impl +LL | / fn partial_cmp(&self, other: &Foo) -> Option { +LL | | None +LL | | } + | |_____- not a trait impl error: aborting due to 4 previous errors