|
1 | 1 | use super::prelude::*; |
2 | | -use crate::session_diagnostics::{FeatureExpectedSingleWord, LimitInvalid}; |
| 2 | +use crate::session_diagnostics::{ExpectedSingleWord, LimitInvalid}; |
3 | 3 |
|
4 | 4 | pub(crate) struct CrateNameParser; |
5 | 5 |
|
@@ -186,7 +186,64 @@ impl<S: Stage> CombineAttributeParser<S> for FeatureParser { |
186 | 186 | let path = elem.path(); |
187 | 187 | let Some(ident) = path.word() else { |
188 | 188 | let first_segment = elem.path().segments().next().expect("at least one segment"); |
189 | | - cx.emit_err(FeatureExpectedSingleWord { |
| 189 | + cx.emit_err(ExpectedSingleWord { |
| 190 | + description: "rust features", |
| 191 | + span: path.span(), |
| 192 | + first_segment_span: first_segment.span, |
| 193 | + first_segment: first_segment.name, |
| 194 | + }); |
| 195 | + continue; |
| 196 | + }; |
| 197 | + |
| 198 | + res.push(ident); |
| 199 | + } |
| 200 | + |
| 201 | + res |
| 202 | + } |
| 203 | +} |
| 204 | + |
| 205 | +pub(crate) struct RegisterToolParser; |
| 206 | + |
| 207 | +impl<S: Stage> CombineAttributeParser<S> for RegisterToolParser { |
| 208 | + const PATH: &[Symbol] = &[sym::register_tool]; |
| 209 | + type Item = Ident; |
| 210 | + const CONVERT: ConvertFn<Self::Item> = AttributeKind::RegisterTool; |
| 211 | + |
| 212 | + // FIXME: recursion limit is allowed on all targets and ignored, |
| 213 | + // even though it should only be valid on crates of course |
| 214 | + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); |
| 215 | + const TEMPLATE: AttributeTemplate = template!(List: &["tool1, tool2, ..."]); |
| 216 | + |
| 217 | + fn extend<'c>( |
| 218 | + cx: &'c mut AcceptContext<'_, '_, S>, |
| 219 | + args: &'c ArgParser<'_>, |
| 220 | + ) -> impl IntoIterator<Item = Self::Item> + 'c { |
| 221 | + let ArgParser::List(list) = args else { |
| 222 | + cx.expected_list(cx.attr_span); |
| 223 | + return Vec::new(); |
| 224 | + }; |
| 225 | + |
| 226 | + if list.is_empty() { |
| 227 | + cx.warn_empty_attribute(cx.attr_span); |
| 228 | + } |
| 229 | + |
| 230 | + let mut res = Vec::new(); |
| 231 | + |
| 232 | + for elem in list.mixed() { |
| 233 | + let Some(elem) = elem.meta_item() else { |
| 234 | + cx.expected_identifier(elem.span()); |
| 235 | + continue; |
| 236 | + }; |
| 237 | + if let Err(arg_span) = elem.args().no_args() { |
| 238 | + cx.expected_no_args(arg_span); |
| 239 | + continue; |
| 240 | + } |
| 241 | + |
| 242 | + let path = elem.path(); |
| 243 | + let Some(ident) = path.word() else { |
| 244 | + let first_segment = elem.path().segments().next().expect("at least one segment"); |
| 245 | + cx.emit_err(ExpectedSingleWord { |
| 246 | + description: "tools", |
190 | 247 | span: path.span(), |
191 | 248 | first_segment_span: first_segment.span, |
192 | 249 | first_segment: first_segment.name, |
|
0 commit comments