• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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