diff options
Diffstat (limited to 'compiler/rustc_attr_parsing/src/attributes')
5 files changed, 115 insertions, 37 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 0a340cd5e93..20ec0fd0c7b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,40 +1,4 @@ -use std::num::IntErrorKind; - -use rustc_hir::limit::Limit; - use super::prelude::*; -use crate::session_diagnostics::LimitInvalid; - -impl<S: Stage> AcceptContext<'_, '_, S> { - fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> { - let Some(limit) = nv.value_as_str() else { - self.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); - return None; - }; - - let error_str = match limit.as_str().parse() { - Ok(i) => return Some(Limit::new(i)), - Err(e) => match e.kind() { - IntErrorKind::PosOverflow => "`limit` is too large", - IntErrorKind::Empty => "`limit` must be a non-negative integer", - IntErrorKind::InvalidDigit => "not a valid integer", - IntErrorKind::NegOverflow => { - panic!( - "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead" - ) - } - IntErrorKind::Zero => { - panic!("zero is a valid `limit` so should have returned Ok() when parsing") - } - kind => panic!("unimplemented IntErrorKind variant: {:?}", kind), - }, - }; - - self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str }); - - None - } -} pub(crate) struct CrateNameParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs new file mode 100644 index 00000000000..56ff10be426 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -0,0 +1,60 @@ +use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType}; + +use super::prelude::*; + +pub(crate) struct DebuggerViualizerParser; + +impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser { + const PATH: &[Symbol] = &[sym::debugger_visualizer]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]); + const TEMPLATE: AttributeTemplate = template!( + List: &[r#"natvis_file = "...", gdb_script_file = "...""#], + "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute" + ); + + type Item = DebugVisualizer; + const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c { + let Some(l) = args.list() else { + cx.expected_list(args.span().unwrap_or(cx.attr_span)); + return None; + }; + let Some(single) = l.single() else { + cx.expected_single_argument(l.span); + return None; + }; + let Some(mi) = single.meta_item() else { + cx.expected_name_value(single.span(), None); + return None; + }; + let path = mi.path().word_sym(); + let visualizer_type = match path { + Some(sym::natvis_file) => DebuggerVisualizerType::Natvis, + Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter, + _ => { + cx.expected_specific_argument( + mi.path().span(), + &[sym::natvis_file, sym::gdb_script_file], + ); + return None; + } + }; + + let Some(path) = mi.args().name_value() else { + cx.expected_name_value(single.span(), path); + return None; + }; + + let Some(path) = path.value_as_str() else { + cx.expected_string_literal(path.value_span, Some(path.value_as_lit())); + return None; + }; + + Some(DebugVisualizer { span: mi.span(), visualizer_type, path }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 4ed13d239b9..8dbf4c0ef32 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -36,6 +36,7 @@ pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod crate_level; +pub(crate) mod debugger; pub(crate) mod deprecation; pub(crate) mod dummy; pub(crate) mod inline; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index a995549fc7c..cf2f5c6c790 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -49,3 +49,21 @@ impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser { Some(AttributeKind::RustcObjectLifetimeDefault) } } + +pub(crate) struct RustcSimdMonomorphizeLaneLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser { + const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?)) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 77e8c32e59d..62b72798e96 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -1,11 +1,15 @@ +use std::num::IntErrorKind; + use rustc_ast::LitKind; use rustc_ast::attr::AttributeExt; use rustc_feature::is_builtin_attr_name; use rustc_hir::RustcVersion; +use rustc_hir::limit::Limit; use rustc_span::{Symbol, sym}; use crate::context::{AcceptContext, Stage}; -use crate::parser::ArgParser; +use crate::parser::{ArgParser, NameValueParser}; +use crate::session_diagnostics::LimitInvalid; /// Parse a rustc version number written inside string literal in an attribute, /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are @@ -85,3 +89,34 @@ pub(crate) fn parse_single_integer<S: Stage>( }; Some(num.0) } + +impl<S: Stage> AcceptContext<'_, '_, S> { + pub(crate) fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> { + let Some(limit) = nv.value_as_str() else { + self.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + + let error_str = match limit.as_str().parse() { + Ok(i) => return Some(Limit::new(i)), + Err(e) => match e.kind() { + IntErrorKind::PosOverflow => "`limit` is too large", + IntErrorKind::Empty => "`limit` must be a non-negative integer", + IntErrorKind::InvalidDigit => "not a valid integer", + IntErrorKind::NegOverflow => { + panic!( + "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead" + ) + } + IntErrorKind::Zero => { + panic!("zero is a valid `limit` so should have returned Ok() when parsing") + } + kind => panic!("unimplemented IntErrorKind variant: {:?}", kind), + }, + }; + + self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str }); + + None + } +} |
