|
1 | 1 | #![deny(unused_must_use)] |
2 | 2 |
|
| 3 | +use std::str::FromStr; |
| 4 | + |
3 | 5 | use proc_macro2::{Ident, Span, TokenStream}; |
4 | 6 | use quote::{format_ident, quote, quote_spanned}; |
5 | 7 | use syn::spanned::Spanned; |
@@ -215,9 +217,22 @@ impl DiagnosticDeriveVariantBuilder { |
215 | 217 | tokens.extend(quote! { |
216 | 218 | diag.code(#code); |
217 | 219 | }); |
| 220 | + } else if path.is_ident("msrv") { |
| 221 | + let msrv = nested.parse::<syn::LitStr>()?; |
| 222 | + if let Ok(RustVersion { major, minor, patch }) = msrv.value().parse() { |
| 223 | + tokens.extend(quote! { |
| 224 | + diag.set_rust_version(::rustc_errors::RustVersion { |
| 225 | + major: #major, |
| 226 | + minor: #minor, |
| 227 | + patch: #patch, |
| 228 | + }); |
| 229 | + }); |
| 230 | + } else { |
| 231 | + span_err(msrv.span().unwrap(), "failed to parse rust version").emit(); |
| 232 | + }; |
218 | 233 | } else { |
219 | 234 | span_err(path.span().unwrap(), "unknown argument") |
220 | | - .note("only the `code` parameter is valid after the slug") |
| 235 | + .note("only `code` or `msrv`are valid after the slug") |
221 | 236 | .emit(); |
222 | 237 |
|
223 | 238 | // consume the buffer so we don't have syntax errors from syn |
@@ -504,3 +519,34 @@ impl DiagnosticDeriveVariantBuilder { |
504 | 519 | } |
505 | 520 | } |
506 | 521 | } |
| 522 | + |
| 523 | +// FIXME: Duplicated in `rustc_errors` |
| 524 | +#[derive(Copy, Clone, Debug)] |
| 525 | +struct RustVersion { |
| 526 | + major: u64, |
| 527 | + minor: u64, |
| 528 | + patch: u64, |
| 529 | +} |
| 530 | + |
| 531 | +impl FromStr for RustVersion { |
| 532 | + type Err = (); |
| 533 | + |
| 534 | + fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 535 | + fn get_number(s: &str) -> Result<(u64, &str), ()> { |
| 536 | + let end = s.chars().take_while(char::is_ascii_digit).count(); |
| 537 | + if end == 0 { |
| 538 | + return Err(()); |
| 539 | + } |
| 540 | + // `is_ascii_digit` ensures that this will be on a char boundary |
| 541 | + let (num, rest) = s.split_at(end); |
| 542 | + Ok((num.parse().map_err(|_| ())?, rest)) |
| 543 | + } |
| 544 | + |
| 545 | + let (major, s) = get_number(s)?; |
| 546 | + let s = s.strip_prefix(".").ok_or(())?; |
| 547 | + let (minor, s) = get_number(s)?; |
| 548 | + let s = s.strip_prefix(".").ok_or(())?; |
| 549 | + let (patch, _) = get_number(s)?; |
| 550 | + Ok(Self { major, minor, patch }) |
| 551 | + } |
| 552 | +} |
0 commit comments