| use rustc_feature::AttributeStability; | |
| use rustc_hir::attrs::{CrateType, WindowsSubsystemKind}; | |
| use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES; | |
| use rustc_span::Symbol; | |
| use rustc_span::edit_distance::find_best_match_for_name_with_substrings; | |
| use super::prelude::*; | |
| use crate::diagnostics::{UnknownCrateTypes, UnknownCrateTypesSuggestion}; | |
| pub(crate) struct CrateNameParser; | |
| impl SingleAttributeParser for CrateNameParser { | |
| const PATH: &[Symbol] = &[sym::crate_name]; | |
| const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; | |
| const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { | |
| let n = cx.expect_name_value(args, cx.attr_span, None)?; | |
| let name = cx.expect_string_literal(n)?; | |
| Some(AttributeKind::CrateName { name, name_span: n.value_span, attr_span: cx.attr_span }) | |
| } | |
| } | |
| pub(crate) struct CrateTypeParser; | |
| impl CombineAttributeParser for CrateTypeParser { | |
| const PATH: &[Symbol] = &[sym::crate_type]; | |
| type Item = CrateType; | |
| const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::CrateType(items); | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const TEMPLATE: AttributeTemplate = | |
| template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html"); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| fn extend( | |
| cx: &mut AcceptContext<'_, '_>, | |
| args: &ArgParser, | |
| ) -> impl IntoIterator<Item = Self::Item> { | |
| let n = cx.expect_name_value(args, cx.attr_span, None)?; | |
| let crate_type = cx.expect_string_literal(n)?; | |
| let Ok(crate_type) = crate_type.try_into() else { | |
| // We don't error on invalid `#![crate_type]` when not applied to a crate | |
| if cx.shared.target == Target::Crate { | |
| let candidate = find_best_match_for_name_with_substrings( | |
| &CrateType::all_stable().iter().map(|(name, _)| *name).collect::<Vec<_>>(), | |
| crate_type, | |
| Some(5), | |
| ); | |
| let span = n.value_span; | |
| cx.emit_lint( | |
| UNKNOWN_CRATE_TYPES, | |
| UnknownCrateTypes { | |
| sugg: candidate.map(|s| UnknownCrateTypesSuggestion { span, snippet: s }), | |
| }, | |
| span, | |
| ); | |
| } | |
| return None; | |
| }; | |
| Some(crate_type) | |
| } | |
| } | |
| pub(crate) struct RecursionLimitParser; | |
| impl SingleAttributeParser for RecursionLimitParser { | |
| const PATH: &[Symbol] = &[sym::recursion_limit]; | |
| const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; | |
| const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { | |
| let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| Some(AttributeKind::RecursionLimit { limit: cx.parse_limit_int(nv)? }) | |
| } | |
| } | |
| pub(crate) struct MoveSizeLimitParser; | |
| impl SingleAttributeParser for MoveSizeLimitParser { | |
| const PATH: &[Symbol] = &[sym::move_size_limit]; | |
| const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(large_assignments); | |
| fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { | |
| let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| Some(AttributeKind::MoveSizeLimit { limit: cx.parse_limit_int(nv)? }) | |
| } | |
| } | |
| pub(crate) struct TypeLengthLimitParser; | |
| impl SingleAttributeParser for TypeLengthLimitParser { | |
| const PATH: &[Symbol] = &[sym::type_length_limit]; | |
| const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; | |
| const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { | |
| let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| Some(AttributeKind::TypeLengthLimit { limit: cx.parse_limit_int(nv)? }) | |
| } | |
| } | |
| pub(crate) struct PatternComplexityLimitParser; | |
| impl SingleAttributeParser for PatternComplexityLimitParser { | |
| const PATH: &[Symbol] = &[sym::pattern_complexity_limit]; | |
| const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!( | |
| rustc_attrs, | |
| "the `#[pattern_complexity_limit]` attribute is used for rustc unit tests" | |
| ); | |
| fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { | |
| let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| Some(AttributeKind::PatternComplexityLimit { limit: cx.parse_limit_int(nv)? }) | |
| } | |
| } | |
| pub(crate) struct NoCoreParser; | |
| impl NoArgsAttributeParser for NoCoreParser { | |
| const PATH: &[Symbol] = &[sym::no_core]; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(no_core); | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoCore; | |
| } | |
| pub(crate) struct NoStdParser; | |
| impl NoArgsAttributeParser for NoStdParser { | |
| const PATH: &[Symbol] = &[sym::no_std]; | |
| const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoStd; | |
| } | |
| pub(crate) struct NoMainParser; | |
| impl NoArgsAttributeParser for NoMainParser { | |
| const PATH: &[Symbol] = &[sym::no_main]; | |
| const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain; | |
| } | |
| pub(crate) struct RustcCoherenceIsCoreParser; | |
| impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { | |
| const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(rustc_attrs); | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCoherenceIsCore; | |
| } | |
| pub(crate) struct WindowsSubsystemParser; | |
| impl SingleAttributeParser for WindowsSubsystemParser { | |
| const PATH: &[Symbol] = &[sym::windows_subsystem]; | |
| const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { | |
| let nv = cx.expect_name_value(args, cx.inner_span, Some(sym::windows_subsystem))?; | |
| let kind = match nv.value_as_str() { | |
| Some(sym::console) => WindowsSubsystemKind::Console, | |
| Some(sym::windows) => WindowsSubsystemKind::Windows, | |
| Some(_) | None => { | |
| cx.adcx().expected_specific_argument_strings( | |
| nv.value_span, | |
| &[sym::console, sym::windows], | |
| ); | |
| return None; | |
| } | |
| }; | |
| Some(AttributeKind::WindowsSubsystem(kind)) | |
| } | |
| } | |
| pub(crate) struct PanicRuntimeParser; | |
| impl NoArgsAttributeParser for PanicRuntimeParser { | |
| const PATH: &[Symbol] = &[sym::panic_runtime]; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(panic_runtime); | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime; | |
| } | |
| pub(crate) struct NeedsPanicRuntimeParser; | |
| impl NoArgsAttributeParser for NeedsPanicRuntimeParser { | |
| const PATH: &[Symbol] = &[sym::needs_panic_runtime]; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(needs_panic_runtime); | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime; | |
| } | |
| pub(crate) struct ProfilerRuntimeParser; | |
| impl NoArgsAttributeParser for ProfilerRuntimeParser { | |
| const PATH: &[Symbol] = &[sym::profiler_runtime]; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(profiler_runtime); | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime; | |
| } | |
| pub(crate) struct NoBuiltinsParser; | |
| impl NoArgsAttributeParser for NoBuiltinsParser { | |
| const PATH: &[Symbol] = &[sym::no_builtins]; | |
| const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins; | |
| } | |
| pub(crate) struct RustcPreserveUbChecksParser; | |
| impl NoArgsAttributeParser for RustcPreserveUbChecksParser { | |
| const PATH: &[Symbol] = &[sym::rustc_preserve_ub_checks]; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(rustc_attrs); | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcPreserveUbChecks; | |
| } | |
| pub(crate) struct RustcNoImplicitBoundsParser; | |
| impl NoArgsAttributeParser for RustcNoImplicitBoundsParser { | |
| const PATH: &[Symbol] = &[sym::rustc_no_implicit_bounds]; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(rustc_attrs); | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds; | |
| } | |
| pub(crate) struct DefaultLibAllocatorParser; | |
| impl NoArgsAttributeParser for DefaultLibAllocatorParser { | |
| const PATH: &[Symbol] = &[sym::default_lib_allocator]; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const STABILITY: AttributeStability = unstable!(allocator_internals); | |
| const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator; | |
| } | |
| pub(crate) struct FeatureParser; | |
| impl CombineAttributeParser for FeatureParser { | |
| const PATH: &[Symbol] = &[sym::feature]; | |
| type Item = Ident; | |
| const CONVERT: ConvertFn<Self::Item> = AttributeKind::Feature; | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = | |
| AllowedTargets::AllowListWarnRest(&[Allow(Target::Crate)]); | |
| const TEMPLATE: AttributeTemplate = template!(List: &["feature1, feature2, ..."]); | |
| const STABILITY: AttributeStability = AttributeStability::Stable; | |
| fn extend( | |
| cx: &mut AcceptContext<'_, '_>, | |
| args: &ArgParser, | |
| ) -> impl IntoIterator<Item = Self::Item> { | |
| let Some(list) = cx.expect_list(args, cx.attr_span) else { | |
| return Vec::new(); | |
| }; | |
| if list.is_empty() { | |
| let attr_span = cx.attr_span; | |
| cx.adcx().warn_empty_attribute(attr_span); | |
| } | |
| let mut res = Vec::new(); | |
| for elem in list.mixed() { | |
| let Some(elem) = elem.meta_item() else { | |
| cx.adcx().expected_identifier(elem.span()); | |
| continue; | |
| }; | |
| let Some(()) = cx.expect_no_args(elem.args()) else { | |
| continue; | |
| }; | |
| let path = elem.path(); | |
| let Some(ident) = path.word() else { | |
| cx.adcx().expected_identifier(path.span()); | |
| continue; | |
| }; | |
| res.push(ident); | |
| } | |
| res | |
| } | |
| } | |
| pub(crate) struct RegisterToolParser; | |
| impl CombineAttributeParser for RegisterToolParser { | |
| const PATH: &[Symbol] = &[sym::register_tool]; | |
| type Item = Ident; | |
| const CONVERT: ConvertFn<Self::Item> = |tools, _span| AttributeKind::RegisterTool(tools); | |
| const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]); | |
| const TEMPLATE: AttributeTemplate = template!(List: &["tool1, tool2, ..."]); | |
| const STABILITY: AttributeStability = unstable!(register_tool); | |
| fn extend( | |
| cx: &mut AcceptContext<'_, '_>, | |
| args: &ArgParser, | |
| ) -> impl IntoIterator<Item = Self::Item> { | |
| let Some(list) = cx.expect_list(args, cx.attr_span) else { | |
| return Vec::new(); | |
| }; | |
| if list.is_empty() { | |
| let attr_span = cx.attr_span; | |
| cx.adcx().warn_empty_attribute(attr_span); | |
| } | |
| let mut res = Vec::new(); | |
| for elem in list.mixed() { | |
| let Some(elem) = elem.meta_item() else { | |
| cx.adcx().expected_identifier(elem.span()); | |
| continue; | |
| }; | |
| let Some(()) = cx.expect_no_args(elem.args()) else { | |
| continue; | |
| }; | |
| let path = elem.path(); | |
| let Some(ident) = path.word() else { | |
| cx.adcx().expected_identifier(path.span()); | |
| continue; | |
| }; | |
| res.push(ident); | |
| } | |
| res | |
| } | |
| } |