Port do_not_recommend to new attr parsing

This commit is contained in:
mejrs 2026-01-13 16:29:02 +01:00
parent db1484bdee
commit a1e2cea685
17 changed files with 65 additions and 66 deletions

View file

@ -0,0 +1,31 @@
use rustc_feature::{AttributeTemplate, template};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::{Symbol, sym};
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
pub(crate) struct DoNotRecommendParser;
impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr.
const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let attr_span = cx.attr_span;
if !matches!(args, ArgParser::NoArgs) {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::DoNotRecommendDoesNotExpectArgs,
attr_span,
);
}
Some(AttributeKind::DoNotRecommend { attr_span })
}
}

View file

@ -39,6 +39,7 @@ pub(crate) mod confusables;
pub(crate) mod crate_level;
pub(crate) mod debugger;
pub(crate) mod deprecation;
pub(crate) mod do_not_recommend;
pub(crate) mod doc;
pub(crate) mod dummy;
pub(crate) mod inline;

View file

@ -34,6 +34,7 @@ use crate::attributes::crate_level::{
};
use crate::attributes::debugger::DebuggerViualizerParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::do_not_recommend::DoNotRecommendParser;
use crate::attributes::doc::DocParser;
use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@ -197,6 +198,7 @@ attribute_parsers!(
Single<CrateNameParser>,
Single<CustomMirParser>,
Single<DeprecationParser>,
Single<DoNotRecommendParser>,
Single<DummyParser>,
Single<ExportNameParser>,
Single<IgnoreParser>,

View file

@ -731,6 +731,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_do_not_implement_via_object]`.
DoNotImplementViaObject(Span),
/// Represents `#[diagnostic::do_not_recommend]`.
DoNotRecommend { attr_span: Span },
/// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
/// Represents all other uses of the [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html)
/// attribute.

View file

@ -44,6 +44,7 @@ impl AttributeKind {
DenyExplicitImpl(..) => No,
Deprecation { .. } => Yes,
DoNotImplementViaObject(..) => No,
DoNotRecommend { .. } => Yes,
Doc(_) => Yes,
DocComment { .. } => Yes,
Dummy => No,

View file

@ -480,6 +480,9 @@ lint_improper_ctypes_unsafe_binder = unsafe binders are incompatible with foreig
lint_improper_gpu_kernel_arg = passing type `{$ty}` to a function with "gpu-kernel" ABI may have unexpected behavior
.help = use primitive types and raw pointers to get reliable behavior
lint_incorrect_do_not_recommend_args =
`#[diagnostic::do_not_recommend]` does not expect any arguments
lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a pointer without provenance
.note = this is dangerous because dereferencing the resulting pointer is undefined behavior
.note_exposed_provenance = exposed provenance semantics can be used to create a pointer based on some previously exposed provenance

View file

@ -419,5 +419,9 @@ pub fn decorate_attribute_lint(
&AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.decorate_lint(diag),
&AttributeLintKind::AttrCrateLevelOnly => lints::AttrCrateLevelOnly.decorate_lint(diag),
&AttributeLintKind::DoNotRecommendDoesNotExpectArgs => {
lints::DoNotRecommendDoesNotExpectArgs.decorate_lint(diag)
}
}
}

View file

@ -3317,3 +3317,7 @@ pub(crate) struct DocTestLiteral;
#[diag(lint_attr_crate_level)]
#[note]
pub(crate) struct AttrCrateLevelOnly;
#[derive(LintDiagnostic)]
#[diag(lint_incorrect_do_not_recommend_args)]
pub(crate) struct DoNotRecommendDoesNotExpectArgs;

View file

@ -821,6 +821,7 @@ pub enum AttributeLintKind {
},
DocTestLiteral,
AttrCrateLevelOnly,
DoNotRecommendDoesNotExpectArgs,
}
pub type RegisteredTools = FxIndexSet<Ident>;

View file

@ -3540,7 +3540,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Whether this is a trait implementation that has `#[diagnostic::do_not_recommend]`
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()
find_attr!(self.get_all_attrs(def_id), AttributeKind::DoNotRecommend { .. })
}
pub fn is_trivial_const<P>(self, def_id: P) -> bool

View file

@ -51,7 +51,7 @@ use rustc_query_system::ich::StableHashingContext;
use rustc_serialize::{Decodable, Encodable};
pub use rustc_session::lint::RegisteredTools;
use rustc_span::hygiene::MacroKind;
use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, sym};
use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol};
pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet};
pub use rustc_type_ir::fast_reject::DeepRejectCtxt;
#[allow(
@ -1819,37 +1819,6 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Get an attribute from the diagnostic attribute namespace
///
/// This function requests an attribute with the following structure:
///
/// `#[diagnostic::$attr]`
///
/// This function performs feature checking, so if an attribute is returned
/// it can be used by the consumer
pub fn get_diagnostic_attr(
self,
did: impl Into<DefId>,
attr: Symbol,
) -> Option<&'tcx hir::Attribute> {
let did: DefId = did.into();
if did.as_local().is_some() {
// it's a crate local item, we need to check feature flags
if rustc_feature::is_stable_diagnostic_attribute(attr, self.features()) {
self.get_attrs_by_path(did, &[sym::diagnostic, sym::do_not_recommend]).next()
} else {
None
}
} else {
// we filter out unstable diagnostic attributes before
// encoding attributes
debug_assert!(rustc_feature::encode_cross_crate(attr));
self.attrs_for_def(did)
.iter()
.find(|a| matches!(a.path().as_ref(), [sym::diagnostic, a] if *a == attr))
}
}
pub fn get_attrs_by_path(
self,
did: DefId,

View file

@ -246,9 +246,6 @@ passes_implied_feature_not_exist =
passes_incorrect_crate_type = lang items are not allowed in stable dylibs
passes_incorrect_do_not_recommend_args =
`#[diagnostic::do_not_recommend]` does not expect any arguments
passes_incorrect_do_not_recommend_location =
`#[diagnostic::do_not_recommend]` can only be placed on trait implementations

View file

@ -43,8 +43,8 @@ use rustc_middle::{bug, span_bug};
use rustc_session::config::CrateType;
use rustc_session::lint;
use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES,
UNUSED_ATTRIBUTES,
};
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition;
@ -223,6 +223,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::RustcMustImplementOneOf { attr_span, fn_names }) => {
self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id,target)
},
Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)},
Attribute::Parsed(
AttributeKind::EiiDeclaration { .. }
| AttributeKind::EiiForeignItem
@ -313,9 +314,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
match attr.path().as_slice() {
[sym::diagnostic, sym::do_not_recommend, ..] => {
self.check_do_not_recommend(attr.span(), hir_id, target, attr, item)
}
[sym::diagnostic, sym::on_unimplemented, ..] => {
self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
}
@ -568,14 +566,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
/// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl and that it has no
/// arguments.
/// 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,
attr: &Attribute,
item: Option<ItemLike<'_>>,
) {
if !matches!(target, Target::Impl { .. })
@ -592,14 +588,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
errors::IncorrectDoNotRecommendLocation,
);
}
if !attr.is_word() {
self.tcx.emit_node_span_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
hir_id,
attr_span,
errors::DoNotRecommendDoesNotExpectArgs,
);
}
}
/// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition

View file

@ -20,10 +20,6 @@ use crate::lang_items::Duplicate;
#[diag(passes_incorrect_do_not_recommend_location)]
pub(crate) struct IncorrectDoNotRecommendLocation;
#[derive(LintDiagnostic)]
#[diag(passes_incorrect_do_not_recommend_args)]
pub(crate) struct DoNotRecommendDoesNotExpectArgs;
#[derive(Diagnostic)]
#[diag(passes_autodiff_attr)]
pub(crate) struct AutoDiffAttr {

View file

@ -434,7 +434,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
} = candidate.kind()
&& tcx.do_not_recommend_impl(impl_def_id)
{
trace!("#[do_not_recommend] -> exit");
trace!("#[diagnostic::do_not_recommend] -> exit");
return ControlFlow::Break(self.obligation.clone());
}

View file

@ -729,14 +729,6 @@ help: use `#[rustc_align(...)]` instead
LL | #[repr]
| ^^^^^^^
warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
--> $DIR/malformed-attrs.rs:155:1
|
LL | #[diagnostic::do_not_recommend()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: missing options for `on_unimplemented` attribute
--> $DIR/malformed-attrs.rs:144:1
|
@ -744,6 +736,7 @@ LL | #[diagnostic::on_unimplemented]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: at least one of the `message`, `note` and `label` options are expected
= note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: malformed `on_unimplemented` attribute
--> $DIR/malformed-attrs.rs:146:1
@ -823,6 +816,12 @@ LL | #[no_implicit_prelude = 23]
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= help: `#[no_implicit_prelude]` can be applied to crates and modules
warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
--> $DIR/malformed-attrs.rs:155:1
|
LL | #[diagnostic::do_not_recommend()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: `#[automatically_derived]` attribute cannot be used on modules
--> $DIR/malformed-attrs.rs:196:1
|

View file

@ -11,5 +11,5 @@ use ::std::prelude::rust_2015::*;
"My Label", note = "Note 1", note = "Note 2")]
trait ImportantTrait<A> { }
#[diagnostic::do_not_recommend]
#[attr = DoNotRecommend]
impl <T> ImportantTrait<T> for T where T: Clone { }