about summary refs log tree commit diff
path: root/compiler/rustc_macros/src
diff options
context:
space:
mode:
authorJubilee <46493976+workingjubilee@users.noreply.github.com>2023-10-28 01:07:38 -0700
committerGitHub <noreply@github.com>2023-10-28 01:07:38 -0700
commit1db8c9d6e20dfefda97fd994e09e7c3121fd2e45 (patch)
tree582976dc0da17d85b409f00ae6b7edb696114166 /compiler/rustc_macros/src
parent87a564d271999dafcc9bcfdcca33fd5fa60b0e58 (diff)
parentb7debe34e6fb2d329e21739c97ce3d7161303af5 (diff)
downloadrust-1db8c9d6e20dfefda97fd994e09e7c3121fd2e45.tar.gz
rust-1db8c9d6e20dfefda97fd994e09e7c3121fd2e45.zip
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.

https://github.com/rust-lang/rust/blob/dab715641e96a61a534587fda9de1128b75b34dc/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs#L385

https://github.com/rust-lang/rust/blob/dab715641e96a61a534587fda9de1128b75b34dc/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.
Diffstat (limited to 'compiler/rustc_macros/src')
-rw-r--r--compiler/rustc_macros/src/current_version.rs59
-rw-r--r--compiler/rustc_macros/src/lib.rs6
2 files changed, 65 insertions, 0 deletions
diff --git a/compiler/rustc_macros/src/current_version.rs b/compiler/rustc_macros/src/current_version.rs
new file mode 100644
index 00000000000..5e3b91c17bf
--- /dev/null
+++ b/compiler/rustc_macros/src/current_version.rs
@@ -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 })
+    }
+}
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 776ba8f9ca1..193dbd75fbd 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -15,6 +15,7 @@ use synstructure::decl_derive;
 
 use proc_macro::TokenStream;
 
+mod current_version;
 mod diagnostics;
 mod hash_stable;
 mod lift;
@@ -26,6 +27,11 @@ 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)
 }