Rollup merge of #117256 - dtolnay:currentversion, r=compiler-errors
Parse rustc version at compile time This PR eliminates a couple awkward codepaths where it was not clear how the compiler should proceed if its own version number is incomprehensible.dab715641e/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs (L385)
dab715641e/compiler/rustc_attr/src/builtin.rs (L630)
We can guarantee that every compiled rustc comes with a working version number, so the ICE codepaths above shouldn't need to be written.
This commit is contained in:
commit
1db8c9d6e2
9 changed files with 124 additions and 61 deletions
59
compiler/rustc_macros/src/current_version.rs
Normal file
59
compiler/rustc_macros/src/current_version.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use quote::quote;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::{parenthesized, parse_macro_input, LitStr, Token};
|
||||
|
||||
pub struct Input {
|
||||
variable: LitStr,
|
||||
}
|
||||
|
||||
mod kw {
|
||||
syn::custom_keyword!(env);
|
||||
}
|
||||
|
||||
impl Parse for Input {
|
||||
// Input syntax is `env!("CFG_RELEASE")` to facilitate grepping.
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let paren;
|
||||
input.parse::<kw::env>()?;
|
||||
input.parse::<Token![!]>()?;
|
||||
parenthesized!(paren in input);
|
||||
let variable: LitStr = paren.parse()?;
|
||||
Ok(Input { variable })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_version(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as Input);
|
||||
|
||||
TokenStream::from(match RustcVersion::parse_env_var(&input.variable) {
|
||||
Ok(RustcVersion { major, minor, patch }) => quote!(
|
||||
Self { major: #major, minor: #minor, patch: #patch }
|
||||
),
|
||||
Err(err) => syn::Error::new(Span::call_site(), err).into_compile_error(),
|
||||
})
|
||||
}
|
||||
|
||||
struct RustcVersion {
|
||||
major: u16,
|
||||
minor: u16,
|
||||
patch: u16,
|
||||
}
|
||||
|
||||
impl RustcVersion {
|
||||
fn parse_env_var(env_var: &LitStr) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let value = proc_macro::tracked_env::var(env_var.value())?;
|
||||
Self::parse_str(&value)
|
||||
.ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into())
|
||||
}
|
||||
|
||||
fn parse_str(value: &str) -> Option<Self> {
|
||||
// Ignore any suffixes such as "-dev" or "-nightly".
|
||||
let mut components = value.split('-').next().unwrap().splitn(3, '.');
|
||||
let major = components.next()?.parse().ok()?;
|
||||
let minor = components.next()?.parse().ok()?;
|
||||
let patch = components.next().unwrap_or("0").parse().ok()?;
|
||||
Some(RustcVersion { major, minor, patch })
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ use synstructure::decl_derive;
|
|||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
mod current_version;
|
||||
mod diagnostics;
|
||||
mod hash_stable;
|
||||
mod lift;
|
||||
|
@ -25,6 +26,11 @@ mod symbols;
|
|||
mod type_foldable;
|
||||
mod type_visitable;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn current_rustc_version(input: TokenStream) -> TokenStream {
|
||||
current_version::current_version(input)
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
||||
query::rustc_queries(input)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue