1 use crate::common::{Config, Debugger};
2 use crate::header::IgnoreDecision;
3 use crate::util;
4
handle_needs( cache: &CachedNeedsConditions, config: &Config, ln: &str, ) -> IgnoreDecision5 pub(super) fn handle_needs(
6 cache: &CachedNeedsConditions,
7 config: &Config,
8 ln: &str,
9 ) -> IgnoreDecision {
10 // Note thet we intentionally still put the needs- prefix here to make the file show up when
11 // grepping for a directive name, even though we could technically strip that.
12 let needs = &[
13 Need {
14 name: "needs-asm-support",
15 condition: config.has_asm_support(),
16 ignore_reason: "ignored on targets without inline assembly support",
17 },
18 Need {
19 name: "needs-sanitizer-support",
20 condition: cache.sanitizer_support,
21 ignore_reason: "ignored on targets without sanitizers support",
22 },
23 Need {
24 name: "needs-sanitizer-address",
25 condition: cache.sanitizer_address,
26 ignore_reason: "ignored on targets without address sanitizer",
27 },
28 Need {
29 name: "needs-sanitizer-cfi",
30 condition: cache.sanitizer_cfi,
31 ignore_reason: "ignored on targets without CFI sanitizer",
32 },
33 Need {
34 name: "needs-sanitizer-kcfi",
35 condition: cache.sanitizer_kcfi,
36 ignore_reason: "ignored on targets without kernel CFI sanitizer",
37 },
38 Need {
39 name: "needs-sanitizer-kasan",
40 condition: cache.sanitizer_kasan,
41 ignore_reason: "ignored on targets without kernel address sanitizer",
42 },
43 Need {
44 name: "needs-sanitizer-leak",
45 condition: cache.sanitizer_leak,
46 ignore_reason: "ignored on targets without leak sanitizer",
47 },
48 Need {
49 name: "needs-sanitizer-memory",
50 condition: cache.sanitizer_memory,
51 ignore_reason: "ignored on targets without memory sanitizer",
52 },
53 Need {
54 name: "needs-sanitizer-thread",
55 condition: cache.sanitizer_thread,
56 ignore_reason: "ignored on targets without thread sanitizer",
57 },
58 Need {
59 name: "needs-sanitizer-hwaddress",
60 condition: cache.sanitizer_hwaddress,
61 ignore_reason: "ignored on targets without hardware-assisted address sanitizer",
62 },
63 Need {
64 name: "needs-sanitizer-memtag",
65 condition: cache.sanitizer_memtag,
66 ignore_reason: "ignored on targets without memory tagging sanitizer",
67 },
68 Need {
69 name: "needs-sanitizer-shadow-call-stack",
70 condition: cache.sanitizer_shadow_call_stack,
71 ignore_reason: "ignored on targets without shadow call stacks",
72 },
73 Need {
74 name: "needs-sanitizer-safestack",
75 condition: cache.sanitizer_safestack,
76 ignore_reason: "ignored on targets without SafeStack support",
77 },
78 Need {
79 name: "needs-run-enabled",
80 condition: config.run_enabled(),
81 ignore_reason: "ignored when running the resulting test binaries is disabled",
82 },
83 Need {
84 name: "needs-unwind",
85 condition: config.can_unwind(),
86 ignore_reason: "ignored on targets without unwinding support",
87 },
88 Need {
89 name: "needs-profiler-support",
90 condition: cache.profiler_support,
91 ignore_reason: "ignored when profiler support is disabled",
92 },
93 Need {
94 name: "needs-matching-clang",
95 condition: config.run_clang_based_tests_with.is_some(),
96 ignore_reason: "ignored when the used clang does not match the built LLVM",
97 },
98 Need {
99 name: "needs-xray",
100 condition: cache.xray,
101 ignore_reason: "ignored on targets without xray tracing",
102 },
103 Need {
104 name: "needs-rust-lld",
105 condition: cache.rust_lld,
106 ignore_reason: "ignored on targets without Rust's LLD",
107 },
108 Need {
109 name: "needs-rust-lldb",
110 condition: config.debugger != Some(Debugger::Lldb) || config.lldb_native_rust,
111 ignore_reason: "ignored on targets without Rust's LLDB",
112 },
113 Need {
114 name: "needs-i686-dlltool",
115 condition: cache.i686_dlltool,
116 ignore_reason: "ignored when dlltool for i686 is not present",
117 },
118 Need {
119 name: "needs-x86_64-dlltool",
120 condition: cache.x86_64_dlltool,
121 ignore_reason: "ignored when dlltool for x86_64 is not present",
122 },
123 Need {
124 name: "needs-dlltool",
125 condition: cache.dlltool,
126 ignore_reason: "ignored when dlltool for the current architecture is not present",
127 },
128 Need {
129 name: "needs-git-hash",
130 condition: config.git_hash,
131 ignore_reason: "ignored when git hashes have been omitted for building",
132 },
133 Need {
134 name: "needs-dynamic-linking",
135 condition: config.target_cfg().dynamic_linking,
136 ignore_reason: "ignored on targets without dynamic linking",
137 },
138 ];
139
140 let (name, comment) = match ln.split_once([':', ' ']) {
141 Some((name, comment)) => (name, Some(comment)),
142 None => (ln, None),
143 };
144
145 if !name.starts_with("needs-") {
146 return IgnoreDecision::Continue;
147 }
148
149 // Handled elsewhere.
150 if name == "needs-llvm-components" {
151 return IgnoreDecision::Continue;
152 }
153
154 let mut found_valid = false;
155 for need in needs {
156 if need.name == name {
157 if need.condition {
158 found_valid = true;
159 break;
160 } else {
161 return IgnoreDecision::Ignore {
162 reason: if let Some(comment) = comment {
163 format!("{} ({comment})", need.ignore_reason)
164 } else {
165 need.ignore_reason.into()
166 },
167 };
168 }
169 }
170 }
171
172 if found_valid {
173 IgnoreDecision::Continue
174 } else {
175 IgnoreDecision::Error { message: format!("invalid needs directive: {name}") }
176 }
177 }
178
179 struct Need {
180 name: &'static str,
181 condition: bool,
182 ignore_reason: &'static str,
183 }
184
185 pub(super) struct CachedNeedsConditions {
186 sanitizer_support: bool,
187 sanitizer_address: bool,
188 sanitizer_cfi: bool,
189 sanitizer_kcfi: bool,
190 sanitizer_kasan: bool,
191 sanitizer_leak: bool,
192 sanitizer_memory: bool,
193 sanitizer_thread: bool,
194 sanitizer_hwaddress: bool,
195 sanitizer_memtag: bool,
196 sanitizer_shadow_call_stack: bool,
197 sanitizer_safestack: bool,
198 profiler_support: bool,
199 xray: bool,
200 rust_lld: bool,
201 i686_dlltool: bool,
202 x86_64_dlltool: bool,
203 dlltool: bool,
204 }
205
206 impl CachedNeedsConditions {
load(config: &Config) -> Self207 pub(super) fn load(config: &Config) -> Self {
208 let path = std::env::var_os("PATH").expect("missing PATH environment variable");
209 let path = std::env::split_paths(&path).collect::<Vec<_>>();
210
211 // On Windows, dlltool.exe is used for all architectures.
212 #[cfg(windows)]
213 let dlltool = path.iter().any(|dir| dir.join("dlltool.exe").is_file());
214
215 // For non-Windows, there are architecture specific dlltool binaries.
216 #[cfg(not(windows))]
217 let i686_dlltool = path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file());
218 #[cfg(not(windows))]
219 let x86_64_dlltool =
220 path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file());
221
222 let target = &&*config.target;
223 Self {
224 sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
225 sanitizer_address: util::ASAN_SUPPORTED_TARGETS.contains(target),
226 sanitizer_cfi: util::CFI_SUPPORTED_TARGETS.contains(target),
227 sanitizer_kcfi: util::KCFI_SUPPORTED_TARGETS.contains(target),
228 sanitizer_kasan: util::KASAN_SUPPORTED_TARGETS.contains(target),
229 sanitizer_leak: util::LSAN_SUPPORTED_TARGETS.contains(target),
230 sanitizer_memory: util::MSAN_SUPPORTED_TARGETS.contains(target),
231 sanitizer_thread: util::TSAN_SUPPORTED_TARGETS.contains(target),
232 sanitizer_hwaddress: util::HWASAN_SUPPORTED_TARGETS.contains(target),
233 sanitizer_memtag: util::MEMTAG_SUPPORTED_TARGETS.contains(target),
234 sanitizer_shadow_call_stack: util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(target),
235 sanitizer_safestack: util::SAFESTACK_SUPPORTED_TARGETS.contains(target),
236 profiler_support: std::env::var_os("RUSTC_PROFILER_SUPPORT").is_some(),
237 xray: util::XRAY_SUPPORTED_TARGETS.contains(target),
238
239 // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find
240 // whether `rust-lld` is present in the compiler under test.
241 //
242 // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For
243 // example:
244 // - on linux, it can be <sysroot>/lib
245 // - on windows, it can be <sysroot>/bin
246 //
247 // However, `rust-lld` is only located under the lib path, so we look for it there.
248 rust_lld: config
249 .compile_lib_path
250 .parent()
251 .expect("couldn't traverse to the parent of the specified --compile-lib-path")
252 .join("lib")
253 .join("rustlib")
254 .join(target)
255 .join("bin")
256 .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
257 .exists(),
258
259 #[cfg(windows)]
260 i686_dlltool: dlltool,
261 #[cfg(windows)]
262 x86_64_dlltool: dlltool,
263 #[cfg(windows)]
264 dlltool,
265
266 // For non-Windows, there are architecture specific dlltool binaries.
267 #[cfg(not(windows))]
268 i686_dlltool,
269 #[cfg(not(windows))]
270 x86_64_dlltool,
271 #[cfg(not(windows))]
272 dlltool: if config.matches_arch("x86") {
273 i686_dlltool
274 } else if config.matches_arch("x86_64") {
275 x86_64_dlltool
276 } else {
277 false
278 },
279 }
280 }
281 }
282