Skip to content

Commit 2cff3e9

Browse files
committed
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.
1 parent e8ada6a commit 2cff3e9

File tree

22 files changed

+228
-209
lines changed

22 files changed

+228
-209
lines changed

compiler/rustc_ast/src/attr/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::util::literal::escape_string_symbol;
1313
use rustc_index::bit_set::GrowableBitSet;
1414
use rustc_span::symbol::{sym, Ident, Symbol};
1515
use rustc_span::Span;
16+
use smallvec::{smallvec, SmallVec};
1617
use std::iter;
1718
use std::sync::atomic::{AtomicU32, Ordering};
1819
use thin_vec::{thin_vec, ThinVec};
@@ -87,10 +88,20 @@ impl Attribute {
8788
AttrKind::DocComment(..) => None,
8889
}
8990
}
91+
9092
pub fn name_or_empty(&self) -> Symbol {
9193
self.ident().unwrap_or_else(Ident::empty).name
9294
}
9395

96+
pub fn path(&self) -> SmallVec<[Symbol; 1]> {
97+
match &self.kind {
98+
AttrKind::Normal(normal) => {
99+
normal.item.path.segments.iter().map(|s| s.ident.name).collect()
100+
}
101+
AttrKind::DocComment(..) => smallvec![sym::doc],
102+
}
103+
}
104+
94105
#[inline]
95106
pub fn has_name(&self, name: Symbol) -> bool {
96107
match &self.kind {

compiler/rustc_feature/src/builtin_attrs.rs

-6
Original file line numberDiff line numberDiff line change
@@ -515,12 +515,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
515515
EncodeCrossCrate::Yes, experimental!(deprecated_safe),
516516
),
517517

518-
// RFC 2397
519-
gated!(
520-
do_not_recommend, Normal, template!(Word), WarnFollowing,
521-
EncodeCrossCrate::Yes, experimental!(do_not_recommend)
522-
),
523-
524518
// `#[cfi_encoding = ""]`
525519
gated!(
526520
cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,

compiler/rustc_middle/src/ty/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,11 @@ impl<'tcx> TyCtxt<'tcx> {
18051805
self.get_attrs(did, attr).next().is_some()
18061806
}
18071807

1808+
/// Determines whether an item is annotated with a multi-segement attribute
1809+
pub fn has_attrs_with_path(self, did: impl Into<DefId>, attrs: &[Symbol]) -> bool {
1810+
self.get_attrs_by_path(did.into(), attrs).next().is_some()
1811+
}
1812+
18081813
/// Returns `true` if this is an `auto trait`.
18091814
pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
18101815
self.trait_def(trait_def_id).has_auto_impl

compiler/rustc_passes/messages.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ passes_implied_feature_not_exist =
341341
feature `{$implied_by}` implying `{$feature}` does not exist
342342
343343
passes_incorrect_do_not_recommend_location =
344-
`#[do_not_recommend]` can only be placed on trait implementations
344+
`#[diagnostic::do_not_recommend]` can only be placed on trait implementations
345345
346346
passes_incorrect_meta_item = expected a quoted string literal
347347
passes_incorrect_meta_item_suggestion = consider surrounding this with quotes

compiler/rustc_passes/src/check_attr.rs

+75-62
Original file line numberDiff line numberDiff line change
@@ -116,92 +116,96 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
116116
let mut seen = FxHashMap::default();
117117
let attrs = self.tcx.hir().attrs(hir_id);
118118
for attr in attrs {
119-
if attr.path_matches(&[sym::diagnostic, sym::on_unimplemented]) {
120-
self.check_diagnostic_on_unimplemented(attr.span, hir_id, target);
121-
}
122-
match attr.name_or_empty() {
123-
sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
124-
sym::inline => self.check_inline(hir_id, attr, span, target),
125-
sym::coverage => self.check_coverage(hir_id, attr, span, target),
126-
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
127-
sym::marker => self.check_marker(hir_id, attr, span, target),
128-
sym::target_feature => self.check_target_feature(hir_id, attr, span, target, attrs),
129-
sym::thread_local => self.check_thread_local(attr, span, target),
130-
sym::track_caller => {
119+
match attr.path().as_slice() {
120+
[sym::diagnostic, sym::do_not_recommend] => {
121+
self.check_do_not_recommend(attr.span, hir_id, target)
122+
}
123+
[sym::diagnostic, sym::on_unimplemented] => {
124+
self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
125+
}
126+
[sym::inline] => self.check_inline(hir_id, attr, span, target),
127+
[sym::coverage] => self.check_coverage(hir_id, attr, span, target),
128+
[sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target),
129+
[sym::marker] => self.check_marker(hir_id, attr, span, target),
130+
[sym::target_feature] => {
131+
self.check_target_feature(hir_id, attr, span, target, attrs)
132+
}
133+
[sym::thread_local] => self.check_thread_local(attr, span, target),
134+
[sym::track_caller] => {
131135
self.check_track_caller(hir_id, attr.span, attrs, span, target)
132136
}
133-
sym::doc => self.check_doc_attrs(
137+
[sym::doc] => self.check_doc_attrs(
134138
attr,
135139
hir_id,
136140
target,
137141
&mut specified_inline,
138142
&mut doc_aliases,
139143
),
140-
sym::no_link => self.check_no_link(hir_id, attr, span, target),
141-
sym::export_name => self.check_export_name(hir_id, attr, span, target),
142-
sym::rustc_layout_scalar_valid_range_start
143-
| sym::rustc_layout_scalar_valid_range_end => {
144+
[sym::no_link] => self.check_no_link(hir_id, attr, span, target),
145+
[sym::export_name] => self.check_export_name(hir_id, attr, span, target),
146+
[sym::rustc_layout_scalar_valid_range_start]
147+
| [sym::rustc_layout_scalar_valid_range_end] => {
144148
self.check_rustc_layout_scalar_valid_range(attr, span, target)
145149
}
146-
sym::allow_internal_unstable => {
150+
[sym::allow_internal_unstable] => {
147151
self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
148152
}
149-
sym::debugger_visualizer => self.check_debugger_visualizer(attr, target),
150-
sym::rustc_allow_const_fn_unstable => {
153+
[sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target),
154+
[sym::rustc_allow_const_fn_unstable] => {
151155
self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
152156
}
153-
sym::rustc_std_internal_symbol => {
157+
[sym::rustc_std_internal_symbol] => {
154158
self.check_rustc_std_internal_symbol(attr, span, target)
155159
}
156-
sym::naked => self.check_naked(hir_id, attr, span, target),
157-
sym::rustc_never_returns_null_ptr => {
160+
[sym::naked] => self.check_naked(hir_id, attr, span, target),
161+
[sym::rustc_never_returns_null_ptr] => {
158162
self.check_applied_to_fn_or_method(hir_id, attr, span, target)
159163
}
160-
sym::rustc_legacy_const_generics => {
164+
[sym::rustc_legacy_const_generics] => {
161165
self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
162166
}
163-
sym::rustc_lint_query_instability => {
167+
[sym::rustc_lint_query_instability] => {
164168
self.check_rustc_lint_query_instability(hir_id, attr, span, target)
165169
}
166-
sym::rustc_lint_diagnostics => {
170+
[sym::rustc_lint_diagnostics] => {
167171
self.check_rustc_lint_diagnostics(hir_id, attr, span, target)
168172
}
169-
sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(attr, span, target),
170-
sym::rustc_lint_opt_deny_field_access => {
173+
[sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target),
174+
[sym::rustc_lint_opt_deny_field_access] => {
171175
self.check_rustc_lint_opt_deny_field_access(attr, span, target)
172176
}
173-
sym::rustc_clean
174-
| sym::rustc_dirty
175-
| sym::rustc_if_this_changed
176-
| sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(attr),
177-
sym::rustc_coinductive
178-
| sym::rustc_must_implement_one_of
179-
| sym::rustc_deny_explicit_impl
180-
| sym::const_trait => self.check_must_be_applied_to_trait(attr, span, target),
181-
sym::cmse_nonsecure_entry => {
177+
[sym::rustc_clean]
178+
| [sym::rustc_dirty]
179+
| [sym::rustc_if_this_changed]
180+
| [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr),
181+
[sym::rustc_coinductive]
182+
| [sym::rustc_must_implement_one_of]
183+
| [sym::rustc_deny_explicit_impl]
184+
| [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target),
185+
[sym::cmse_nonsecure_entry] => {
182186
self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
183187
}
184-
sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
185-
sym::must_not_suspend => self.check_must_not_suspend(attr, span, target),
186-
sym::must_use => self.check_must_use(hir_id, attr, target),
187-
sym::rustc_pass_by_value => self.check_pass_by_value(attr, span, target),
188-
sym::rustc_allow_incoherent_impl => {
188+
[sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target),
189+
[sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target),
190+
[sym::must_use] => self.check_must_use(hir_id, attr, target),
191+
[sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target),
192+
[sym::rustc_allow_incoherent_impl] => {
189193
self.check_allow_incoherent_impl(attr, span, target)
190194
}
191-
sym::rustc_has_incoherent_inherent_impls => {
195+
[sym::rustc_has_incoherent_inherent_impls] => {
192196
self.check_has_incoherent_inherent_impls(attr, span, target)
193197
}
194-
sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target),
195-
sym::ffi_const => self.check_ffi_const(attr.span, target),
196-
sym::rustc_const_unstable
197-
| sym::rustc_const_stable
198-
| sym::unstable
199-
| sym::stable
200-
| sym::rustc_allowed_through_unstable_modules
201-
| sym::rustc_promotable => self.check_stability_promotable(attr, target),
202-
sym::link_ordinal => self.check_link_ordinal(attr, span, target),
203-
sym::rustc_confusables => self.check_confusables(attr, target),
204-
sym::rustc_safe_intrinsic => {
198+
[sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target),
199+
[sym::ffi_const] => self.check_ffi_const(attr.span, target),
200+
[sym::rustc_const_unstable]
201+
| [sym::rustc_const_stable]
202+
| [sym::unstable]
203+
| [sym::stable]
204+
| [sym::rustc_allowed_through_unstable_modules]
205+
| [sym::rustc_promotable] => self.check_stability_promotable(attr, target),
206+
[sym::link_ordinal] => self.check_link_ordinal(attr, span, target),
207+
[sym::rustc_confusables] => self.check_confusables(attr, target),
208+
[sym::rustc_safe_intrinsic] => {
205209
self.check_rustc_safe_intrinsic(hir_id, attr, span, target)
206210
}
207211
_ => true,
@@ -293,18 +297,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
293297
);
294298
}
295299

296-
/// Checks if `#[do_not_recommend]` is applied on a trait impl.
297-
fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool {
298-
if let Target::Impl = target {
299-
true
300-
} else {
301-
self.dcx().emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
302-
false
300+
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl.
301+
fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) -> bool {
302+
if !matches!(target, Target::Impl) {
303+
self.tcx.emit_node_span_lint(
304+
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
305+
hir_id,
306+
attr_span,
307+
errors::IncorrectDoNotRecommendLocation,
308+
);
303309
}
310+
true
304311
}
305312

306313
/// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
307-
fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
314+
fn check_diagnostic_on_unimplemented(
315+
&self,
316+
attr_span: Span,
317+
hir_id: HirId,
318+
target: Target,
319+
) -> bool {
308320
if !matches!(target, Target::Trait) {
309321
self.tcx.emit_node_span_lint(
310322
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
@@ -313,6 +325,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
313325
DiagnosticOnUnimplementedOnlyForTraits,
314326
);
315327
}
328+
true
316329
}
317330

318331
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.

compiler/rustc_passes/src/errors.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@ use rustc_span::{Span, Symbol, DUMMY_SP};
1717
use crate::check_attr::ProcMacroKind;
1818
use crate::lang_items::Duplicate;
1919

20-
#[derive(Diagnostic)]
20+
#[derive(LintDiagnostic)]
2121
#[diag(passes_incorrect_do_not_recommend_location)]
22-
pub struct IncorrectDoNotRecommendLocation {
23-
#[primary_span]
24-
pub span: Span,
25-
}
22+
pub struct IncorrectDoNotRecommendLocation;
2623

2724
#[derive(LintDiagnostic)]
2825
#[diag(passes_outer_crate_level_attr)]

compiler/rustc_resolve/src/macros.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
567567
if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
568568
&& let [namespace, attribute, ..] = &*path.segments
569569
&& namespace.ident.name == sym::diagnostic
570-
&& attribute.ident.name != sym::on_unimplemented
570+
&& !(attribute.ident.name == sym::on_unimplemented
571+
|| (attribute.ident.name == sym::do_not_recommend
572+
&& self.tcx.features().do_not_recommend))
571573
{
572574
let distance =
573575
edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);

compiler/rustc_trait_selection/src/solve/fulfill.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
380380
source: CandidateSource::Impl(impl_def_id),
381381
result: _,
382382
} = candidate.kind()
383-
&& goal.infcx().tcx.has_attr(impl_def_id, sym::do_not_recommend)
383+
&& goal
384+
.infcx()
385+
.tcx
386+
.has_attrs_with_path(impl_def_id, &[sym::diagnostic, sym::do_not_recommend])
384387
{
385388
return ControlFlow::Break(self.obligation.clone());
386389
}

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
10121012
let mut base_cause = obligation.cause.code().clone();
10131013
loop {
10141014
if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
1015-
if self.tcx.has_attr(c.impl_or_alias_def_id, sym::do_not_recommend) {
1015+
if self.tcx.has_attrs_with_path(
1016+
c.impl_or_alias_def_id,
1017+
&[sym::diagnostic, sym::do_not_recommend],
1018+
) {
10161019
let code = (*c.derived.parent_code).clone();
10171020
obligation.cause.map_code(|_| code);
10181021
obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);

tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl<T> Expression for Bound<T> {
2626
type SqlType = T;
2727
}
2828

29-
#[do_not_recommend]
29+
#[diagnostic::do_not_recommend]
3030
impl<T, ST> AsExpression<ST> for T
3131
where
3232
T: Expression<SqlType = ST>,

tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs renamed to tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
#![feature(do_not_recommend)]
22

3-
pub trait Foo {
4-
}
3+
pub trait Foo {}
54

6-
impl Foo for i32 {
7-
}
5+
impl Foo for i32 {}
86

9-
pub trait Bar {
10-
}
7+
pub trait Bar {}
118

12-
#[do_not_recommend]
13-
impl<T: Foo> Bar for T {
14-
}
9+
#[diagnostic::do_not_recommend]
10+
impl<T: Foo> Bar for T {}
1511

1612
fn stuff<T: Bar>(_: T) {}
1713

tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr renamed to tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0277]: the trait bound `u8: Bar` is not satisfied
2-
--> $DIR/feature-gate-do_not_recommend.rs:19:11
2+
--> $DIR/feature-gate-do_not_recommend.rs:15:11
33
|
44
LL | stuff(1u8);
55
| ^^^ the trait `Bar` is not implemented for `u8`
66
|
77
note: required by a bound in `stuff`
8-
--> $DIR/feature-gate-do_not_recommend.rs:16:13
8+
--> $DIR/feature-gate-do_not_recommend.rs:12:13
99
|
1010
LL | fn stuff<T: Bar>(_: T) {}
1111
| ^^^ required by this bound in `stuff`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//@ check-pass
2+
#![feature(do_not_recommend)]
3+
4+
#[diagnostic::do_not_recommend]
5+
//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
6+
const CONST: () = ();
7+
8+
#[diagnostic::do_not_recommend]
9+
//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
10+
static STATIC: () = ();
11+
12+
#[diagnostic::do_not_recommend]
13+
//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
14+
type Type = ();
15+
16+
#[diagnostic::do_not_recommend]
17+
//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
18+
enum Enum {}
19+
20+
#[diagnostic::do_not_recommend]
21+
//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
22+
extern "C" {}
23+
24+
#[diagnostic::do_not_recommend]
25+
//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
26+
fn fun() {}
27+
28+
#[diagnostic::do_not_recommend]
29+
//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
30+
struct Struct {}
31+
32+
#[diagnostic::do_not_recommend]
33+
//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
34+
trait Trait {}
35+
36+
#[diagnostic::do_not_recommend]
37+
impl Trait for i32 {}
38+
39+
fn main() {}

0 commit comments

Comments
 (0)