1 // rustc-cfg emitted by the build script:
2 //
3 // "use_proc_macro"
4 // Link to extern crate proc_macro. Available on any compiler and any target
5 // except wasm32. Requires "proc-macro" Cargo cfg to be enabled (default is
6 // enabled). On wasm32 we never link to proc_macro even if "proc-macro" cfg
7 // is enabled.
8 //
9 // "wrap_proc_macro"
10 // Wrap types from libproc_macro rather than polyfilling the whole API.
11 // Enabled on rustc 1.29+ as long as procmacro2_semver_exempt is not set,
12 // because we can't emulate the unstable API without emulating everything
13 // else. Also enabled unconditionally on nightly, in which case the
14 // procmacro2_semver_exempt surface area is implemented by using the
15 // nightly-only proc_macro API.
16 //
17 // "hygiene"
18 // Enable Span::mixed_site() and non-dummy behavior of Span::resolved_at
19 // and Span::located_at. Enabled on Rust 1.45+.
20 //
21 // "proc_macro_span"
22 // Enable non-dummy behavior of Span::start and Span::end methods which
23 // requires an unstable compiler feature. Enabled when building with
24 // nightly, unless `-Z allow-feature` in RUSTFLAGS disallows unstable
25 // features.
26 //
27 // "super_unstable"
28 // Implement the semver exempt API in terms of the nightly-only proc_macro
29 // API. Enabled when using procmacro2_semver_exempt on a nightly compiler.
30 //
31 // "span_locations"
32 // Provide methods Span::start and Span::end which give the line/column
33 // location of a token. Enabled by procmacro2_semver_exempt or the
34 // "span-locations" Cargo cfg. This is behind a cfg because tracking
35 // location inside spans is a performance hit.
36
37 use std::env;
38 use std::iter;
39 use std::process::{self, Command};
40 use std::str;
41
main()42 fn main() {
43 println!("cargo:rerun-if-changed=build.rs");
44
45 let version = match rustc_version() {
46 Some(version) => version,
47 None => return,
48 };
49
50 if version.minor < 31 {
51 eprintln!("Minimum supported rustc version is 1.31");
52 process::exit(1);
53 }
54
55 let semver_exempt = cfg!(procmacro2_semver_exempt);
56 if semver_exempt {
57 // https://github.com/alexcrichton/proc-macro2/issues/147
58 println!("cargo:rustc-cfg=procmacro2_semver_exempt");
59 }
60
61 if semver_exempt || cfg!(feature = "span-locations") {
62 println!("cargo:rustc-cfg=span_locations");
63 }
64
65 if version.minor < 32 {
66 println!("cargo:rustc-cfg=no_libprocmacro_unwind_safe");
67 }
68
69 if version.minor < 39 {
70 println!("cargo:rustc-cfg=no_bind_by_move_pattern_guard");
71 }
72
73 if version.minor >= 44 {
74 println!("cargo:rustc-cfg=lexerror_display");
75 }
76
77 if version.minor >= 45 {
78 println!("cargo:rustc-cfg=hygiene");
79 }
80
81 if version.minor >= 54 {
82 println!("cargo:rustc-cfg=literal_from_str");
83 }
84
85 let target = env::var("TARGET").unwrap();
86 if !enable_use_proc_macro(&target) {
87 return;
88 }
89
90 println!("cargo:rustc-cfg=use_proc_macro");
91
92 if version.nightly || !semver_exempt {
93 println!("cargo:rustc-cfg=wrap_proc_macro");
94 }
95
96 if version.nightly && feature_allowed("proc_macro_span") {
97 println!("cargo:rustc-cfg=proc_macro_span");
98 }
99
100 if semver_exempt && version.nightly {
101 println!("cargo:rustc-cfg=super_unstable");
102 }
103 }
104
enable_use_proc_macro(target: &str) -> bool105 fn enable_use_proc_macro(target: &str) -> bool {
106 // wasm targets don't have the `proc_macro` crate, disable this feature.
107 if target.contains("wasm32") {
108 return false;
109 }
110
111 // Otherwise, only enable it if our feature is actually enabled.
112 cfg!(feature = "proc-macro")
113 }
114
115 struct RustcVersion {
116 minor: u32,
117 nightly: bool,
118 }
119
rustc_version() -> Option<RustcVersion>120 fn rustc_version() -> Option<RustcVersion> {
121 let rustc = env::var_os("RUSTC")?;
122 let output = Command::new(rustc).arg("--version").output().ok()?;
123 let version = str::from_utf8(&output.stdout).ok()?;
124 let nightly = version.contains("nightly") || version.contains("dev");
125 let mut pieces = version.split('.');
126 if pieces.next() != Some("rustc 1") {
127 return None;
128 }
129 let minor = pieces.next()?.parse().ok()?;
130 Some(RustcVersion { minor, nightly })
131 }
132
feature_allowed(feature: &str) -> bool133 fn feature_allowed(feature: &str) -> bool {
134 // Recognized formats:
135 //
136 // -Z allow-features=feature1,feature2
137 //
138 // -Zallow-features=feature1,feature2
139
140 let flags_var;
141 let flags_var_string;
142 let mut flags_var_split;
143 let mut flags_none;
144 let flags: &mut dyn Iterator<Item = &str> =
145 if let Some(encoded_rustflags) = env::var_os("CARGO_ENCODED_RUSTFLAGS") {
146 flags_var = encoded_rustflags;
147 flags_var_string = flags_var.to_string_lossy();
148 flags_var_split = flags_var_string.split('\x1f');
149 &mut flags_var_split
150 } else if let Some(rustflags) = env::var_os("RUSTFLAGS") {
151 flags_var = rustflags;
152 flags_var_string = flags_var.to_string_lossy();
153 flags_var_split = flags_var_string.split(' ');
154 &mut flags_var_split
155 } else {
156 flags_none = iter::empty();
157 &mut flags_none
158 };
159
160 for mut flag in flags {
161 if flag.starts_with("-Z") {
162 flag = &flag["-Z".len()..];
163 }
164 if flag.starts_with("allow-features=") {
165 flag = &flag["allow-features=".len()..];
166 return flag.split(',').any(|allowed| allowed == feature);
167 }
168 }
169
170 // No allow-features= flag, allowed by default.
171 true
172 }
173