about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-22 04:14:08 +0000
committerbors <bors@rust-lang.org>2024-05-22 04:14:08 +0000
commitb54dd08a84f3c07efbc2aaf63c3df219ae680a03 (patch)
tree698b43cd20f9dfa17f47d596cee409c1f3b0b842
parent54cdc13542ef548e7d7f71cd48cc9e4f239e0e25 (diff)
parent2cff3e90bcd162964546ca9936c209aa952c1af4 (diff)
downloadrust-b54dd08a84f3c07efbc2aaf63c3df219ae680a03.tar.gz
rust-b54dd08a84f3c07efbc2aaf63c3df219ae680a03.zip
Auto merge of #125326 - weiznich:move/do_not_recommend_to_diganostic_namespace, r=compiler-errors
Move `#[do_not_recommend]` to the `#[diagnostic]` namespace

This commit moves the `#[do_not_recommend]` attribute to the `#[diagnostic]` namespace. It still requires
`#![feature(do_not_recommend)]` to work.

r? `@compiler-errors`
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs11
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs5
-rw-r--r--compiler/rustc_passes/messages.ftl2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs137
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--compiler/rustc_resolve/src/macros.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs5
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs (renamed from tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs)14
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr (renamed from tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr)4
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs39
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr52
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/simple.rs2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs2
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs8
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr14
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs45
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr50
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs10
-rw-r--r--tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr13
22 files changed, 228 insertions, 209 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 0684163617f..d5c9fc960c8 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -13,6 +13,7 @@ use crate::util::literal::escape_string_symbol;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
 use std::iter;
 use std::sync::atomic::{AtomicU32, Ordering};
 use thin_vec::{thin_vec, ThinVec};
@@ -87,10 +88,20 @@ impl Attribute {
             AttrKind::DocComment(..) => None,
         }
     }
+
     pub fn name_or_empty(&self) -> Symbol {
         self.ident().unwrap_or_else(Ident::empty).name
     }
 
+    pub fn path(&self) -> SmallVec<[Symbol; 1]> {
+        match &self.kind {
+            AttrKind::Normal(normal) => {
+                normal.item.path.segments.iter().map(|s| s.ident.name).collect()
+            }
+            AttrKind::DocComment(..) => smallvec![sym::doc],
+        }
+    }
+
     #[inline]
     pub fn has_name(&self, name: Symbol) -> bool {
         match &self.kind {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index ebaa9f8d950..0b4a871dd50 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -515,12 +515,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::Yes, experimental!(deprecated_safe),
     ),
 
-    // RFC 2397
-    gated!(
-        do_not_recommend, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::Yes, experimental!(do_not_recommend)
-    ),
-
     // `#[cfi_encoding = ""]`
     gated!(
         cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8bb19bc85ac..f27409894fa 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1814,6 +1814,11 @@ impl<'tcx> TyCtxt<'tcx> {
         self.get_attrs(did, attr).next().is_some()
     }
 
+    /// Determines whether an item is annotated with a multi-segement attribute
+    pub fn has_attrs_with_path(self, did: impl Into<DefId>, attrs: &[Symbol]) -> bool {
+        self.get_attrs_by_path(did.into(), attrs).next().is_some()
+    }
+
     /// Returns `true` if this is an `auto trait`.
     pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
         self.trait_def(trait_def_id).has_auto_impl
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 3deefcaa06c..d850644bb45 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -341,7 +341,7 @@ passes_implied_feature_not_exist =
     feature `{$implied_by}` implying `{$feature}` does not exist
 
 passes_incorrect_do_not_recommend_location =
-    `#[do_not_recommend]` can only be placed on trait implementations
+    `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
 
 passes_incorrect_meta_item = expected a quoted string literal
 passes_incorrect_meta_item_suggestion = consider surrounding this with quotes
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index b1438a542ac..1924533e280 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -113,92 +113,96 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
-            if attr.path_matches(&[sym::diagnostic, sym::on_unimplemented]) {
-                self.check_diagnostic_on_unimplemented(attr.span, hir_id, target);
-            }
-            match attr.name_or_empty() {
-                sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
-                sym::inline => self.check_inline(hir_id, attr, span, target),
-                sym::coverage => self.check_coverage(hir_id, attr, span, target),
-                sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
-                sym::marker => self.check_marker(hir_id, attr, span, target),
-                sym::target_feature => self.check_target_feature(hir_id, attr, span, target, attrs),
-                sym::thread_local => self.check_thread_local(attr, span, target),
-                sym::track_caller => {
+            match attr.path().as_slice() {
+                [sym::diagnostic, sym::do_not_recommend] => {
+                    self.check_do_not_recommend(attr.span, hir_id, target)
+                }
+                [sym::diagnostic, sym::on_unimplemented] => {
+                    self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
+                }
+                [sym::inline] => self.check_inline(hir_id, attr, span, target),
+                [sym::coverage] => self.check_coverage(hir_id, attr, span, target),
+                [sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target),
+                [sym::marker] => self.check_marker(hir_id, attr, span, target),
+                [sym::target_feature] => {
+                    self.check_target_feature(hir_id, attr, span, target, attrs)
+                }
+                [sym::thread_local] => self.check_thread_local(attr, span, target),
+                [sym::track_caller] => {
                     self.check_track_caller(hir_id, attr.span, attrs, span, target)
                 }
-                sym::doc => self.check_doc_attrs(
+                [sym::doc] => self.check_doc_attrs(
                     attr,
                     hir_id,
                     target,
                     &mut specified_inline,
                     &mut doc_aliases,
                 ),
-                sym::no_link => self.check_no_link(hir_id, attr, span, target),
-                sym::export_name => self.check_export_name(hir_id, attr, span, target),
-                sym::rustc_layout_scalar_valid_range_start
-                | sym::rustc_layout_scalar_valid_range_end => {
+                [sym::no_link] => self.check_no_link(hir_id, attr, span, target),
+                [sym::export_name] => self.check_export_name(hir_id, attr, span, target),
+                [sym::rustc_layout_scalar_valid_range_start]
+                | [sym::rustc_layout_scalar_valid_range_end] => {
                     self.check_rustc_layout_scalar_valid_range(attr, span, target)
                 }
-                sym::allow_internal_unstable => {
+                [sym::allow_internal_unstable] => {
                     self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
                 }
-                sym::debugger_visualizer => self.check_debugger_visualizer(attr, target),
-                sym::rustc_allow_const_fn_unstable => {
+                [sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target),
+                [sym::rustc_allow_const_fn_unstable] => {
                     self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
                 }
-                sym::rustc_std_internal_symbol => {
+                [sym::rustc_std_internal_symbol] => {
                     self.check_rustc_std_internal_symbol(attr, span, target)
                 }
-                sym::naked => self.check_naked(hir_id, attr, span, target),
-                sym::rustc_never_returns_null_ptr => {
+                [sym::naked] => self.check_naked(hir_id, attr, span, target),
+                [sym::rustc_never_returns_null_ptr] => {
                     self.check_applied_to_fn_or_method(hir_id, attr, span, target)
                 }
-                sym::rustc_legacy_const_generics => {
+                [sym::rustc_legacy_const_generics] => {
                     self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
                 }
-                sym::rustc_lint_query_instability => {
+                [sym::rustc_lint_query_instability] => {
                     self.check_rustc_lint_query_instability(hir_id, attr, span, target)
                 }
-                sym::rustc_lint_diagnostics => {
+                [sym::rustc_lint_diagnostics] => {
                     self.check_rustc_lint_diagnostics(hir_id, attr, span, target)
                 }
-                sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(attr, span, target),
-                sym::rustc_lint_opt_deny_field_access => {
+                [sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target),
+                [sym::rustc_lint_opt_deny_field_access] => {
                     self.check_rustc_lint_opt_deny_field_access(attr, span, target)
                 }
-                sym::rustc_clean
-                | sym::rustc_dirty
-                | sym::rustc_if_this_changed
-                | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(attr),
-                sym::rustc_coinductive
-                | sym::rustc_must_implement_one_of
-                | sym::rustc_deny_explicit_impl
-                | sym::const_trait => self.check_must_be_applied_to_trait(attr, span, target),
-                sym::cmse_nonsecure_entry => {
+                [sym::rustc_clean]
+                | [sym::rustc_dirty]
+                | [sym::rustc_if_this_changed]
+                | [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr),
+                [sym::rustc_coinductive]
+                | [sym::rustc_must_implement_one_of]
+                | [sym::rustc_deny_explicit_impl]
+                | [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target),
+                [sym::cmse_nonsecure_entry] => {
                     self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
                 }
-                sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
-                sym::must_not_suspend => self.check_must_not_suspend(attr, span, target),
-                sym::must_use => self.check_must_use(hir_id, attr, target),
-                sym::rustc_pass_by_value => self.check_pass_by_value(attr, span, target),
-                sym::rustc_allow_incoherent_impl => {
+                [sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target),
+                [sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target),
+                [sym::must_use] => self.check_must_use(hir_id, attr, target),
+                [sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target),
+                [sym::rustc_allow_incoherent_impl] => {
                     self.check_allow_incoherent_impl(attr, span, target)
                 }
-                sym::rustc_has_incoherent_inherent_impls => {
+                [sym::rustc_has_incoherent_inherent_impls] => {
                     self.check_has_incoherent_inherent_impls(attr, span, target)
                 }
-                sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target),
-                sym::ffi_const => self.check_ffi_const(attr.span, target),
-                sym::rustc_const_unstable
-                | sym::rustc_const_stable
-                | sym::unstable
-                | sym::stable
-                | sym::rustc_allowed_through_unstable_modules
-                | sym::rustc_promotable => self.check_stability_promotable(attr, target),
-                sym::link_ordinal => self.check_link_ordinal(attr, span, target),
-                sym::rustc_confusables => self.check_confusables(attr, target),
-                sym::rustc_safe_intrinsic => {
+                [sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target),
+                [sym::ffi_const] => self.check_ffi_const(attr.span, target),
+                [sym::rustc_const_unstable]
+                | [sym::rustc_const_stable]
+                | [sym::unstable]
+                | [sym::stable]
+                | [sym::rustc_allowed_through_unstable_modules]
+                | [sym::rustc_promotable] => self.check_stability_promotable(attr, target),
+                [sym::link_ordinal] => self.check_link_ordinal(attr, span, target),
+                [sym::rustc_confusables] => self.check_confusables(attr, target),
+                [sym::rustc_safe_intrinsic] => {
                     self.check_rustc_safe_intrinsic(hir_id, attr, span, target)
                 }
                 _ => true,
@@ -290,18 +294,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         );
     }
 
-    /// Checks if `#[do_not_recommend]` is applied on a trait impl.
-    fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool {
-        if let Target::Impl = target {
-            true
-        } else {
-            self.dcx().emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
-            false
+    /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl.
+    fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) -> bool {
+        if !matches!(target, Target::Impl) {
+            self.tcx.emit_node_span_lint(
+                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                hir_id,
+                attr_span,
+                errors::IncorrectDoNotRecommendLocation,
+            );
         }
+        true
     }
 
     /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
-    fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
+    fn check_diagnostic_on_unimplemented(
+        &self,
+        attr_span: Span,
+        hir_id: HirId,
+        target: Target,
+    ) -> bool {
         if !matches!(target, Target::Trait) {
             self.tcx.emit_node_span_lint(
                 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
@@ -310,6 +322,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 DiagnosticOnUnimplementedOnlyForTraits,
             );
         }
+        true
     }
 
     /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index b8586e7e974..180552785fe 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -17,12 +17,9 @@ use rustc_span::{Span, Symbol, DUMMY_SP};
 use crate::check_attr::ProcMacroKind;
 use crate::lang_items::Duplicate;
 
-#[derive(Diagnostic)]
+#[derive(LintDiagnostic)]
 #[diag(passes_incorrect_do_not_recommend_location)]
-pub struct IncorrectDoNotRecommendLocation {
-    #[primary_span]
-    pub span: Span,
-}
+pub struct IncorrectDoNotRecommendLocation;
 
 #[derive(LintDiagnostic)]
 #[diag(passes_outer_crate_level_attr)]
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 092eb1ce2ee..268e7f06d04 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -578,7 +578,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
             && let [namespace, attribute, ..] = &*path.segments
             && namespace.ident.name == sym::diagnostic
-            && attribute.ident.name != sym::on_unimplemented
+            && !(attribute.ident.name == sym::on_unimplemented
+                || (attribute.ident.name == sym::do_not_recommend
+                    && self.tcx.features().do_not_recommend))
         {
             let distance =
                 edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 4933080451d..7291eb00e72 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -380,7 +380,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             source: CandidateSource::Impl(impl_def_id),
             result: _,
         } = candidate.kind()
-            && goal.infcx().tcx.has_attr(impl_def_id, sym::do_not_recommend)
+            && goal
+                .infcx()
+                .tcx
+                .has_attrs_with_path(impl_def_id, &[sym::diagnostic, sym::do_not_recommend])
         {
             return ControlFlow::Break(self.obligation.clone());
         }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 20dfb5e6642..494fca0336c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -1012,7 +1012,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         let mut base_cause = obligation.cause.code().clone();
         loop {
             if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
-                if self.tcx.has_attr(c.impl_or_alias_def_id, sym::do_not_recommend) {
+                if self.tcx.has_attrs_with_path(
+                    c.impl_or_alias_def_id,
+                    &[sym::diagnostic, sym::do_not_recommend],
+                ) {
                     let code = (*c.derived.parent_code).clone();
                     obligation.cause.map_code(|_| code);
                     obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
index 9cdc193d386..5fd5cc54400 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
@@ -26,7 +26,7 @@ impl<T> Expression for Bound<T> {
     type SqlType = T;
 }
 
-#[do_not_recommend]
+#[diagnostic::do_not_recommend]
 impl<T, ST> AsExpression<ST> for T
 where
     T: Expression<SqlType = ST>,
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs
index c9dc1c6e649..5a26d28188c 100644
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs
@@ -1,17 +1,13 @@
 #![feature(do_not_recommend)]
 
-pub trait Foo {
-}
+pub trait Foo {}
 
-impl Foo for i32 {
-}
+impl Foo for i32 {}
 
-pub trait Bar {
-}
+pub trait Bar {}
 
-#[do_not_recommend]
-impl<T: Foo> Bar for T {
-}
+#[diagnostic::do_not_recommend]
+impl<T: Foo> Bar for T {}
 
 fn stuff<T: Bar>(_: T) {}
 
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr
index e6f199445bf..3951231fa2e 100644
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `u8: Bar` is not satisfied
-  --> $DIR/feature-gate-do_not_recommend.rs:19:11
+  --> $DIR/feature-gate-do_not_recommend.rs:15:11
    |
 LL |     stuff(1u8);
    |           ^^^ the trait `Bar` is not implemented for `u8`
    |
 note: required by a bound in `stuff`
-  --> $DIR/feature-gate-do_not_recommend.rs:16:13
+  --> $DIR/feature-gate-do_not_recommend.rs:12:13
    |
 LL | fn stuff<T: Bar>(_: T) {}
    |             ^^^ required by this bound in `stuff`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
new file mode 100644
index 00000000000..400ef83873e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
@@ -0,0 +1,39 @@
+//@ check-pass
+#![feature(do_not_recommend)]
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+const CONST: () = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+static STATIC: () = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+type Type = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+enum Enum {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+extern "C" {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+fn fun() {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+struct Struct {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+trait Trait {}
+
+#[diagnostic::do_not_recommend]
+impl Trait for i32 {}
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr
new file mode 100644
index 00000000000..c83fd46db58
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr
@@ -0,0 +1,52 @@
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:4:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:8:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:12:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:16:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:20:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:24:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:28:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:32:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 8 warnings emitted
+
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
index 6fb15b90138..780649b009c 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
@@ -6,7 +6,7 @@
 
 trait Foo {}
 
-#[do_not_recommend]
+#[diagnostic::do_not_recommend]
 impl<T> Foo for T where T: Send {}
 
 fn needs_foo<T: Foo>() {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
index 695660d3596..fc355bdc4e2 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
@@ -8,7 +8,7 @@ trait Root {}
 trait DontRecommend {}
 trait Other {}
 
-#[do_not_recommend]
+#[diagnostic::do_not_recommend]
 impl<T> Root for T where T: DontRecommend {}
 
 impl<T> DontRecommend for T where T: Other {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs
new file mode 100644
index 00000000000..ccc687aa5b3
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs
@@ -0,0 +1,8 @@
+#![deny(unknown_or_malformed_diagnostic_attributes)]
+trait Foo {}
+
+#[diagnostic::do_not_recommend]
+//~^ ERROR unknown diagnostic attribute [unknown_or_malformed_diagnostic_attributes]
+impl Foo for i32 {}
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr
new file mode 100644
index 00000000000..d8332229d4f
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr
@@ -0,0 +1,14 @@
+error: unknown diagnostic attribute
+  --> $DIR/unstable-feature.rs:4:15
+   |
+LL | #[diagnostic::do_not_recommend]
+   |               ^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unstable-feature.rs:1:9
+   |
+LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs
deleted file mode 100644
index 91863f5e497..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#![feature(do_not_recommend)]
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-const CONST: () = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-static Static: () = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-type Type = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-enum Enum {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-extern {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-fn fun() {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-struct Struct {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-trait Trait {
-}
-
-#[do_not_recommend]
-impl Trait for i32 {
-}
-
-fn main() {
-}
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr
deleted file mode 100644
index 01ebc23c86e..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr
+++ /dev/null
@@ -1,50 +0,0 @@
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:3:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:7:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:11:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:15:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:20:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:25:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:30:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:35:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 8 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs
deleted file mode 100644
index f0c5c222e78..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-trait Foo {
-}
-
-#[do_not_recommend]
-//~^ ERROR the `#[do_not_recommend]` attribute is an experimental feature
-impl Foo for i32 {
-}
-
-fn main() {
-}
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr
deleted file mode 100644
index 02bc51ccd3f..00000000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: the `#[do_not_recommend]` attribute is an experimental feature
-  --> $DIR/unstable-feature.rs:4:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51992 <https://github.com/rust-lang/rust/issues/51992> for more information
-   = help: add `#![feature(do_not_recommend)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.