]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | //! Contains infrastructure for configuring the compiler, including parsing |
2 | //! command-line options. | |
3 | ||
4 | pub use crate::options::*; | |
5 | ||
6 | use crate::lint; | |
7 | use crate::search_paths::SearchPath; | |
8 | use crate::utils::{CanonicalizedPath, NativeLibKind}; | |
9 | use crate::{early_error, early_warn, Session}; | |
10 | ||
11 | use rustc_data_structures::fx::FxHashSet; | |
12 | use rustc_data_structures::impl_stable_hash_via_hash; | |
13 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; | |
14 | ||
15 | use rustc_target::abi::{Align, TargetDataLayout}; | |
16 | use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple}; | |
17 | ||
18 | use crate::parse::CrateConfig; | |
19 | use rustc_feature::UnstableFeatures; | |
20 | use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST}; | |
21 | use rustc_span::source_map::{FileName, FilePathMapping}; | |
22 | use rustc_span::symbol::{sym, Symbol}; | |
23 | use rustc_span::SourceFileHashAlgorithm; | |
24 | ||
25 | use rustc_errors::emitter::HumanReadableErrorType; | |
26 | use rustc_errors::{ColorConfig, HandlerFlags}; | |
27 | ||
28 | use std::collections::btree_map::{ | |
29 | Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, | |
30 | }; | |
31 | use std::collections::{BTreeMap, BTreeSet}; | |
32 | use std::fmt; | |
33 | use std::iter::{self, FromIterator}; | |
34 | use std::path::{Path, PathBuf}; | |
35 | use std::str::{self, FromStr}; | |
36 | ||
37 | bitflags! { | |
38 | #[derive(Default, Encodable, Decodable)] | |
39 | pub struct SanitizerSet: u8 { | |
40 | const ADDRESS = 1 << 0; | |
41 | const LEAK = 1 << 1; | |
42 | const MEMORY = 1 << 2; | |
43 | const THREAD = 1 << 3; | |
44 | } | |
45 | } | |
46 | ||
47 | /// Formats a sanitizer set as a comma separated list of sanitizers' names. | |
48 | impl fmt::Display for SanitizerSet { | |
49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
50 | let mut first = true; | |
51 | for s in *self { | |
52 | let name = match s { | |
53 | SanitizerSet::ADDRESS => "address", | |
54 | SanitizerSet::LEAK => "leak", | |
55 | SanitizerSet::MEMORY => "memory", | |
56 | SanitizerSet::THREAD => "thread", | |
57 | _ => panic!("unrecognized sanitizer {:?}", s), | |
58 | }; | |
59 | if !first { | |
60 | f.write_str(",")?; | |
61 | } | |
62 | f.write_str(name)?; | |
63 | first = false; | |
64 | } | |
65 | Ok(()) | |
66 | } | |
67 | } | |
68 | ||
69 | impl IntoIterator for SanitizerSet { | |
70 | type Item = SanitizerSet; | |
71 | type IntoIter = std::vec::IntoIter<SanitizerSet>; | |
72 | ||
73 | fn into_iter(self) -> Self::IntoIter { | |
74 | [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD] | |
75 | .iter() | |
76 | .copied() | |
77 | .filter(|&s| self.contains(s)) | |
78 | .collect::<Vec<_>>() | |
79 | .into_iter() | |
80 | } | |
81 | } | |
82 | ||
83 | impl<CTX> HashStable<CTX> for SanitizerSet { | |
84 | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | |
85 | self.bits().hash_stable(ctx, hasher); | |
86 | } | |
87 | } | |
88 | ||
89 | /// The different settings that the `-Z strip` flag can have. | |
90 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
91 | pub enum Strip { | |
92 | /// Do not strip at all. | |
93 | None, | |
94 | ||
95 | /// Strip debuginfo. | |
96 | Debuginfo, | |
97 | ||
98 | /// Strip all symbols. | |
99 | Symbols, | |
100 | } | |
101 | ||
102 | /// The different settings that the `-C control-flow-guard` flag can have. | |
103 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
104 | pub enum CFGuard { | |
105 | /// Do not emit Control Flow Guard metadata or checks. | |
106 | Disabled, | |
107 | ||
108 | /// Emit Control Flow Guard metadata but no checks. | |
109 | NoChecks, | |
110 | ||
111 | /// Emit Control Flow Guard metadata and checks. | |
112 | Checks, | |
113 | } | |
114 | ||
115 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] | |
116 | pub enum OptLevel { | |
117 | No, // -O0 | |
118 | Less, // -O1 | |
119 | Default, // -O2 | |
120 | Aggressive, // -O3 | |
121 | Size, // -Os | |
122 | SizeMin, // -Oz | |
123 | } | |
124 | ||
125 | impl_stable_hash_via_hash!(OptLevel); | |
126 | ||
127 | /// This is what the `LtoCli` values get mapped to after resolving defaults and | |
128 | /// and taking other command line options into account. | |
129 | #[derive(Clone, PartialEq)] | |
130 | pub enum Lto { | |
131 | /// Don't do any LTO whatsoever | |
132 | No, | |
133 | ||
134 | /// Do a full crate graph LTO with ThinLTO | |
135 | Thin, | |
136 | ||
137 | /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen | |
138 | /// units). | |
139 | ThinLocal, | |
140 | ||
141 | /// Do a full crate graph LTO with "fat" LTO | |
142 | Fat, | |
143 | } | |
144 | ||
145 | /// The different settings that the `-C lto` flag can have. | |
146 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
147 | pub enum LtoCli { | |
148 | /// `-C lto=no` | |
149 | No, | |
150 | /// `-C lto=yes` | |
151 | Yes, | |
152 | /// `-C lto` | |
153 | NoParam, | |
154 | /// `-C lto=thin` | |
155 | Thin, | |
156 | /// `-C lto=fat` | |
157 | Fat, | |
158 | /// No `-C lto` flag passed | |
159 | Unspecified, | |
160 | } | |
161 | ||
162 | /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a | |
163 | /// document highlighting each span of every statement (including terminators). `Terminator` and | |
164 | /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a | |
165 | /// computed span for the block, representing the entire range, covering the block's terminator and | |
166 | /// all of its statements. | |
167 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
168 | pub enum MirSpanview { | |
169 | /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement` | |
170 | Statement, | |
171 | /// `-Z dump_mir_spanview=terminator` | |
172 | Terminator, | |
173 | /// `-Z dump_mir_spanview=block` | |
174 | Block, | |
175 | } | |
176 | ||
177 | #[derive(Clone, PartialEq, Hash)] | |
178 | pub enum LinkerPluginLto { | |
179 | LinkerPlugin(PathBuf), | |
180 | LinkerPluginAuto, | |
181 | Disabled, | |
182 | } | |
183 | ||
184 | impl LinkerPluginLto { | |
185 | pub fn enabled(&self) -> bool { | |
186 | match *self { | |
187 | LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true, | |
188 | LinkerPluginLto::Disabled => false, | |
189 | } | |
190 | } | |
191 | } | |
192 | ||
193 | #[derive(Clone, PartialEq, Hash)] | |
194 | pub enum SwitchWithOptPath { | |
195 | Enabled(Option<PathBuf>), | |
196 | Disabled, | |
197 | } | |
198 | ||
199 | impl SwitchWithOptPath { | |
200 | pub fn enabled(&self) -> bool { | |
201 | match *self { | |
202 | SwitchWithOptPath::Enabled(_) => true, | |
203 | SwitchWithOptPath::Disabled => false, | |
204 | } | |
205 | } | |
206 | } | |
207 | ||
208 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | |
209 | #[derive(Encodable, Decodable)] | |
210 | pub enum SymbolManglingVersion { | |
211 | Legacy, | |
212 | V0, | |
213 | } | |
214 | ||
215 | impl_stable_hash_via_hash!(SymbolManglingVersion); | |
216 | ||
217 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] | |
218 | pub enum DebugInfo { | |
219 | None, | |
220 | Limited, | |
221 | Full, | |
222 | } | |
223 | ||
224 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] | |
225 | #[derive(Encodable, Decodable)] | |
226 | pub enum OutputType { | |
227 | Bitcode, | |
228 | Assembly, | |
229 | LlvmAssembly, | |
230 | Mir, | |
231 | Metadata, | |
232 | Object, | |
233 | Exe, | |
234 | DepInfo, | |
235 | } | |
236 | ||
237 | impl_stable_hash_via_hash!(OutputType); | |
238 | ||
239 | impl OutputType { | |
240 | fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool { | |
241 | match *self { | |
242 | OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true, | |
243 | OutputType::Bitcode | |
244 | | OutputType::Assembly | |
245 | | OutputType::LlvmAssembly | |
246 | | OutputType::Mir | |
247 | | OutputType::Object => false, | |
248 | } | |
249 | } | |
250 | ||
251 | fn shorthand(&self) -> &'static str { | |
252 | match *self { | |
253 | OutputType::Bitcode => "llvm-bc", | |
254 | OutputType::Assembly => "asm", | |
255 | OutputType::LlvmAssembly => "llvm-ir", | |
256 | OutputType::Mir => "mir", | |
257 | OutputType::Object => "obj", | |
258 | OutputType::Metadata => "metadata", | |
259 | OutputType::Exe => "link", | |
260 | OutputType::DepInfo => "dep-info", | |
261 | } | |
262 | } | |
263 | ||
264 | fn from_shorthand(shorthand: &str) -> Option<Self> { | |
265 | Some(match shorthand { | |
266 | "asm" => OutputType::Assembly, | |
267 | "llvm-ir" => OutputType::LlvmAssembly, | |
268 | "mir" => OutputType::Mir, | |
269 | "llvm-bc" => OutputType::Bitcode, | |
270 | "obj" => OutputType::Object, | |
271 | "metadata" => OutputType::Metadata, | |
272 | "link" => OutputType::Exe, | |
273 | "dep-info" => OutputType::DepInfo, | |
274 | _ => return None, | |
275 | }) | |
276 | } | |
277 | ||
278 | fn shorthands_display() -> String { | |
279 | format!( | |
280 | "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`", | |
281 | OutputType::Bitcode.shorthand(), | |
282 | OutputType::Assembly.shorthand(), | |
283 | OutputType::LlvmAssembly.shorthand(), | |
284 | OutputType::Mir.shorthand(), | |
285 | OutputType::Object.shorthand(), | |
286 | OutputType::Metadata.shorthand(), | |
287 | OutputType::Exe.shorthand(), | |
288 | OutputType::DepInfo.shorthand(), | |
289 | ) | |
290 | } | |
291 | ||
292 | pub fn extension(&self) -> &'static str { | |
293 | match *self { | |
294 | OutputType::Bitcode => "bc", | |
295 | OutputType::Assembly => "s", | |
296 | OutputType::LlvmAssembly => "ll", | |
297 | OutputType::Mir => "mir", | |
298 | OutputType::Object => "o", | |
299 | OutputType::Metadata => "rmeta", | |
300 | OutputType::DepInfo => "d", | |
301 | OutputType::Exe => "", | |
302 | } | |
303 | } | |
304 | } | |
305 | ||
306 | /// The type of diagnostics output to generate. | |
307 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | |
308 | pub enum ErrorOutputType { | |
309 | /// Output meant for the consumption of humans. | |
310 | HumanReadable(HumanReadableErrorType), | |
311 | /// Output that's consumed by other tools such as `rustfix` or the `RLS`. | |
312 | Json { | |
313 | /// Render the JSON in a human readable way (with indents and newlines). | |
314 | pretty: bool, | |
315 | /// The JSON output includes a `rendered` field that includes the rendered | |
316 | /// human output. | |
317 | json_rendered: HumanReadableErrorType, | |
318 | }, | |
319 | } | |
320 | ||
321 | impl Default for ErrorOutputType { | |
322 | fn default() -> Self { | |
323 | Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)) | |
324 | } | |
325 | } | |
326 | ||
327 | /// Parameter to control path trimming. | |
328 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | |
329 | pub enum TrimmedDefPaths { | |
330 | /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query | |
331 | Never, | |
332 | /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug` | |
333 | Always, | |
334 | /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug` | |
335 | GoodPath, | |
336 | } | |
337 | ||
338 | impl Default for TrimmedDefPaths { | |
339 | fn default() -> Self { | |
340 | Self::Never | |
341 | } | |
342 | } | |
343 | ||
344 | /// Use tree-based collections to cheaply get a deterministic `Hash` implementation. | |
345 | /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break | |
346 | /// dependency tracking for command-line arguments. | |
347 | #[derive(Clone, Hash, Debug)] | |
348 | pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>); | |
349 | ||
350 | impl_stable_hash_via_hash!(OutputTypes); | |
351 | ||
352 | impl OutputTypes { | |
353 | pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes { | |
354 | OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone())))) | |
355 | } | |
356 | ||
357 | pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> { | |
358 | self.0.get(key) | |
359 | } | |
360 | ||
361 | pub fn contains_key(&self, key: &OutputType) -> bool { | |
362 | self.0.contains_key(key) | |
363 | } | |
364 | ||
365 | pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> { | |
366 | self.0.keys() | |
367 | } | |
368 | ||
369 | pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> { | |
370 | self.0.values() | |
371 | } | |
372 | ||
373 | pub fn len(&self) -> usize { | |
374 | self.0.len() | |
375 | } | |
376 | ||
377 | // Returns `true` if any of the output types require codegen or linking. | |
378 | pub fn should_codegen(&self) -> bool { | |
379 | self.0.keys().any(|k| match *k { | |
380 | OutputType::Bitcode | |
381 | | OutputType::Assembly | |
382 | | OutputType::LlvmAssembly | |
383 | | OutputType::Mir | |
384 | | OutputType::Object | |
385 | | OutputType::Exe => true, | |
386 | OutputType::Metadata | OutputType::DepInfo => false, | |
387 | }) | |
388 | } | |
389 | ||
390 | // Returns `true` if any of the output types require linking. | |
391 | pub fn should_link(&self) -> bool { | |
392 | self.0.keys().any(|k| match *k { | |
393 | OutputType::Bitcode | |
394 | | OutputType::Assembly | |
395 | | OutputType::LlvmAssembly | |
396 | | OutputType::Mir | |
397 | | OutputType::Metadata | |
398 | | OutputType::Object | |
399 | | OutputType::DepInfo => false, | |
400 | OutputType::Exe => true, | |
401 | }) | |
402 | } | |
403 | } | |
404 | ||
405 | /// Use tree-based collections to cheaply get a deterministic `Hash` implementation. | |
406 | /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That | |
407 | /// would break dependency tracking for command-line arguments. | |
408 | #[derive(Clone)] | |
409 | pub struct Externs(BTreeMap<String, ExternEntry>); | |
410 | ||
411 | #[derive(Clone, Debug)] | |
412 | pub struct ExternEntry { | |
413 | pub location: ExternLocation, | |
414 | /// Indicates this is a "private" dependency for the | |
415 | /// `exported_private_dependencies` lint. | |
416 | /// | |
417 | /// This can be set with the `priv` option like | |
418 | /// `--extern priv:name=foo.rlib`. | |
419 | pub is_private_dep: bool, | |
420 | /// Add the extern entry to the extern prelude. | |
421 | /// | |
422 | /// This can be disabled with the `noprelude` option like | |
423 | /// `--extern noprelude:name`. | |
424 | pub add_prelude: bool, | |
425 | } | |
426 | ||
427 | #[derive(Clone, Debug)] | |
428 | pub enum ExternLocation { | |
429 | /// Indicates to look for the library in the search paths. | |
430 | /// | |
431 | /// Added via `--extern name`. | |
432 | FoundInLibrarySearchDirectories, | |
433 | /// The locations where this extern entry must be found. | |
434 | /// | |
435 | /// The `CrateLoader` is responsible for loading these and figuring out | |
436 | /// which one to use. | |
437 | /// | |
438 | /// Added via `--extern prelude_name=some_file.rlib` | |
439 | ExactPaths(BTreeSet<CanonicalizedPath>), | |
440 | } | |
441 | ||
442 | impl Externs { | |
443 | pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs { | |
444 | Externs(data) | |
445 | } | |
446 | ||
447 | pub fn get(&self, key: &str) -> Option<&ExternEntry> { | |
448 | self.0.get(key) | |
449 | } | |
450 | ||
451 | pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> { | |
452 | self.0.iter() | |
453 | } | |
454 | } | |
455 | ||
456 | impl ExternEntry { | |
457 | fn new(location: ExternLocation) -> ExternEntry { | |
458 | ExternEntry { location, is_private_dep: false, add_prelude: false } | |
459 | } | |
460 | ||
461 | pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> { | |
462 | match &self.location { | |
463 | ExternLocation::ExactPaths(set) => Some(set.iter()), | |
464 | _ => None, | |
465 | } | |
466 | } | |
467 | } | |
468 | ||
469 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
470 | pub enum PrintRequest { | |
471 | FileNames, | |
472 | Sysroot, | |
473 | TargetLibdir, | |
474 | CrateName, | |
475 | Cfg, | |
476 | TargetList, | |
477 | TargetCPUs, | |
478 | TargetFeatures, | |
479 | RelocationModels, | |
480 | CodeModels, | |
481 | TlsModels, | |
482 | TargetSpec, | |
483 | NativeStaticLibs, | |
484 | } | |
485 | ||
486 | #[derive(Copy, Clone)] | |
487 | pub enum BorrowckMode { | |
488 | Mir, | |
489 | Migrate, | |
490 | } | |
491 | ||
492 | impl BorrowckMode { | |
493 | /// Returns whether we should run the MIR-based borrow check, but also fall back | |
494 | /// on the AST borrow check if the MIR-based one errors. | |
495 | pub fn migrate(self) -> bool { | |
496 | match self { | |
497 | BorrowckMode::Mir => false, | |
498 | BorrowckMode::Migrate => true, | |
499 | } | |
500 | } | |
501 | } | |
502 | ||
503 | pub enum Input { | |
504 | /// Load source code from a file. | |
505 | File(PathBuf), | |
506 | /// Load source code from a string. | |
507 | Str { | |
508 | /// A string that is shown in place of a filename. | |
509 | name: FileName, | |
510 | /// An anonymous string containing the source code. | |
511 | input: String, | |
512 | }, | |
513 | } | |
514 | ||
515 | impl Input { | |
516 | pub fn filestem(&self) -> &str { | |
517 | match *self { | |
518 | Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(), | |
519 | Input::Str { .. } => "rust_out", | |
520 | } | |
521 | } | |
522 | ||
523 | pub fn get_input(&mut self) -> Option<&mut String> { | |
524 | match *self { | |
525 | Input::File(_) => None, | |
526 | Input::Str { ref mut input, .. } => Some(input), | |
527 | } | |
528 | } | |
529 | ||
530 | pub fn source_name(&self) -> FileName { | |
531 | match *self { | |
532 | Input::File(ref ifile) => ifile.clone().into(), | |
533 | Input::Str { ref name, .. } => name.clone(), | |
534 | } | |
535 | } | |
536 | } | |
537 | ||
538 | #[derive(Clone, Hash, Debug)] | |
539 | pub struct OutputFilenames { | |
540 | pub out_directory: PathBuf, | |
541 | filestem: String, | |
542 | pub single_output_file: Option<PathBuf>, | |
543 | pub outputs: OutputTypes, | |
544 | } | |
545 | ||
546 | impl_stable_hash_via_hash!(OutputFilenames); | |
547 | ||
548 | pub const RLINK_EXT: &str = "rlink"; | |
549 | pub const RUST_CGU_EXT: &str = "rcgu"; | |
550 | pub const DWARF_OBJECT_EXT: &str = "dwo"; | |
551 | ||
552 | impl OutputFilenames { | |
553 | pub fn new( | |
554 | out_directory: PathBuf, | |
555 | out_filestem: String, | |
556 | single_output_file: Option<PathBuf>, | |
557 | extra: String, | |
558 | outputs: OutputTypes, | |
559 | ) -> Self { | |
560 | OutputFilenames { | |
561 | out_directory, | |
562 | single_output_file, | |
563 | outputs, | |
564 | filestem: format!("{}{}", out_filestem, extra), | |
565 | } | |
566 | } | |
567 | ||
568 | pub fn path(&self, flavor: OutputType) -> PathBuf { | |
569 | self.outputs | |
570 | .get(&flavor) | |
571 | .and_then(|p| p.to_owned()) | |
572 | .or_else(|| self.single_output_file.clone()) | |
573 | .unwrap_or_else(|| self.temp_path(flavor, None)) | |
574 | } | |
575 | ||
576 | /// Gets the path where a compilation artifact of the given type for the | |
577 | /// given codegen unit should be placed on disk. If codegen_unit_name is | |
578 | /// None, a path distinct from those of any codegen unit will be generated. | |
579 | pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf { | |
580 | let extension = flavor.extension(); | |
581 | self.temp_path_ext(extension, codegen_unit_name) | |
582 | } | |
583 | ||
584 | /// Like `temp_path`, but specifically for dwarf objects. | |
585 | pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf { | |
586 | self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name) | |
587 | } | |
588 | ||
589 | /// Like `temp_path`, but also supports things where there is no corresponding | |
590 | /// OutputType, like noopt-bitcode or lto-bitcode. | |
591 | pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { | |
592 | let mut extension = String::new(); | |
593 | ||
594 | if let Some(codegen_unit_name) = codegen_unit_name { | |
595 | extension.push_str(codegen_unit_name); | |
596 | } | |
597 | ||
598 | if !ext.is_empty() { | |
599 | if !extension.is_empty() { | |
600 | extension.push('.'); | |
601 | extension.push_str(RUST_CGU_EXT); | |
602 | extension.push('.'); | |
603 | } | |
604 | ||
605 | extension.push_str(ext); | |
606 | } | |
607 | ||
608 | self.with_extension(&extension) | |
609 | } | |
610 | ||
611 | pub fn with_extension(&self, extension: &str) -> PathBuf { | |
612 | let mut path = self.out_directory.join(&self.filestem); | |
613 | path.set_extension(extension); | |
614 | path | |
615 | } | |
616 | ||
617 | /// Returns the name of the Split DWARF file - this can differ depending on which Split DWARF | |
618 | /// mode is being used, which is the logic that this function is intended to encapsulate. | |
619 | pub fn split_dwarf_filename( | |
620 | &self, | |
621 | split_debuginfo_kind: SplitDebuginfo, | |
622 | cgu_name: Option<&str>, | |
623 | ) -> Option<PathBuf> { | |
624 | self.split_dwarf_path(split_debuginfo_kind, cgu_name) | |
625 | .map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf()) | |
626 | } | |
627 | ||
628 | /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF | |
629 | /// mode is being used, which is the logic that this function is intended to encapsulate. | |
630 | pub fn split_dwarf_path( | |
631 | &self, | |
632 | split_debuginfo_kind: SplitDebuginfo, | |
633 | cgu_name: Option<&str>, | |
634 | ) -> Option<PathBuf> { | |
635 | let obj_out = self.temp_path(OutputType::Object, cgu_name); | |
636 | let dwo_out = self.temp_path_dwo(cgu_name); | |
637 | match split_debuginfo_kind { | |
638 | SplitDebuginfo::Off => None, | |
639 | // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes | |
640 | // (pointing at the path which is being determined here). Use the path to the current | |
641 | // object file. | |
642 | SplitDebuginfo::Packed => Some(obj_out), | |
643 | // Split mode emits the DWARF into a different file, use that path. | |
644 | SplitDebuginfo::Unpacked => Some(dwo_out), | |
645 | } | |
646 | } | |
647 | } | |
648 | ||
649 | pub fn host_triple() -> &'static str { | |
650 | // Get the host triple out of the build environment. This ensures that our | |
651 | // idea of the host triple is the same as for the set of libraries we've | |
652 | // actually built. We can't just take LLVM's host triple because they | |
653 | // normalize all ix86 architectures to i386. | |
654 | // | |
655 | // Instead of grabbing the host triple (for the current host), we grab (at | |
656 | // compile time) the target triple that this rustc is built with and | |
657 | // calling that (at runtime) the host triple. | |
658 | (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE") | |
659 | } | |
660 | ||
661 | impl Default for Options { | |
662 | fn default() -> Options { | |
663 | Options { | |
664 | crate_types: Vec::new(), | |
665 | optimize: OptLevel::No, | |
666 | debuginfo: DebugInfo::None, | |
667 | lint_opts: Vec::new(), | |
668 | lint_cap: None, | |
669 | describe_lints: false, | |
670 | output_types: OutputTypes(BTreeMap::new()), | |
671 | search_paths: vec![], | |
672 | maybe_sysroot: None, | |
673 | target_triple: TargetTriple::from_triple(host_triple()), | |
674 | test: false, | |
675 | incremental: None, | |
676 | debugging_opts: basic_debugging_options(), | |
677 | prints: Vec::new(), | |
678 | borrowck_mode: BorrowckMode::Migrate, | |
679 | cg: basic_codegen_options(), | |
680 | error_format: ErrorOutputType::default(), | |
681 | externs: Externs(BTreeMap::new()), | |
682 | crate_name: None, | |
683 | alt_std_name: None, | |
684 | libs: Vec::new(), | |
685 | unstable_features: UnstableFeatures::Disallow, | |
686 | debug_assertions: true, | |
687 | actually_rustdoc: false, | |
688 | trimmed_def_paths: TrimmedDefPaths::default(), | |
689 | cli_forced_codegen_units: None, | |
690 | cli_forced_thinlto_off: false, | |
691 | remap_path_prefix: Vec::new(), | |
692 | edition: DEFAULT_EDITION, | |
693 | json_artifact_notifications: false, | |
694 | pretty: None, | |
695 | } | |
696 | } | |
697 | } | |
698 | ||
699 | impl Options { | |
700 | /// Returns `true` if there is a reason to build the dep graph. | |
701 | pub fn build_dep_graph(&self) -> bool { | |
702 | self.incremental.is_some() | |
703 | || self.debugging_opts.dump_dep_graph | |
704 | || self.debugging_opts.query_dep_graph | |
705 | } | |
706 | ||
707 | #[inline(always)] | |
708 | pub fn enable_dep_node_debug_strs(&self) -> bool { | |
709 | cfg!(debug_assertions) | |
710 | && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info) | |
711 | } | |
712 | ||
713 | pub fn file_path_mapping(&self) -> FilePathMapping { | |
714 | FilePathMapping::new(self.remap_path_prefix.clone()) | |
715 | } | |
716 | ||
717 | /// Returns `true` if there will be an output file generated. | |
718 | pub fn will_create_output_file(&self) -> bool { | |
719 | !self.debugging_opts.parse_only && // The file is just being parsed | |
720 | !self.debugging_opts.ls // The file is just being queried | |
721 | } | |
722 | ||
723 | #[inline] | |
724 | pub fn share_generics(&self) -> bool { | |
725 | match self.debugging_opts.share_generics { | |
726 | Some(setting) => setting, | |
727 | None => match self.optimize { | |
728 | OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true, | |
729 | OptLevel::Default | OptLevel::Aggressive => false, | |
730 | }, | |
731 | } | |
732 | } | |
733 | } | |
734 | ||
735 | impl DebuggingOptions { | |
736 | pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags { | |
737 | HandlerFlags { | |
738 | can_emit_warnings, | |
739 | treat_err_as_bug: self.treat_err_as_bug, | |
740 | dont_buffer_diagnostics: self.dont_buffer_diagnostics, | |
741 | report_delayed_bugs: self.report_delayed_bugs, | |
742 | macro_backtrace: self.macro_backtrace, | |
743 | deduplicate_diagnostics: self.deduplicate_diagnostics, | |
744 | } | |
745 | } | |
746 | ||
747 | pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { | |
748 | self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) | |
749 | } | |
750 | } | |
751 | ||
752 | // The type of entry function, so users can have their own entry functions | |
753 | #[derive(Copy, Clone, PartialEq, Hash, Debug)] | |
754 | pub enum EntryFnType { | |
755 | Main, | |
756 | Start, | |
757 | } | |
758 | ||
759 | impl_stable_hash_via_hash!(EntryFnType); | |
760 | ||
761 | #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] | |
762 | pub enum CrateType { | |
763 | Executable, | |
764 | Dylib, | |
765 | Rlib, | |
766 | Staticlib, | |
767 | Cdylib, | |
768 | ProcMacro, | |
769 | } | |
770 | ||
771 | impl_stable_hash_via_hash!(CrateType); | |
772 | ||
773 | #[derive(Clone, Hash)] | |
774 | pub enum Passes { | |
775 | Some(Vec<String>), | |
776 | All, | |
777 | } | |
778 | ||
779 | impl Passes { | |
780 | pub fn is_empty(&self) -> bool { | |
781 | match *self { | |
782 | Passes::Some(ref v) => v.is_empty(), | |
783 | Passes::All => false, | |
784 | } | |
785 | } | |
786 | } | |
787 | ||
788 | pub const fn default_lib_output() -> CrateType { | |
789 | CrateType::Rlib | |
790 | } | |
791 | ||
792 | pub fn default_configuration(sess: &Session) -> CrateConfig { | |
793 | let end = &sess.target.endian; | |
794 | let arch = &sess.target.arch; | |
795 | let wordsz = sess.target.pointer_width.to_string(); | |
796 | let os = &sess.target.os; | |
797 | let env = &sess.target.env; | |
798 | let vendor = &sess.target.vendor; | |
799 | let min_atomic_width = sess.target.min_atomic_width(); | |
800 | let max_atomic_width = sess.target.max_atomic_width(); | |
801 | let atomic_cas = sess.target.atomic_cas; | |
802 | let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { | |
803 | sess.fatal(&err); | |
804 | }); | |
805 | ||
806 | let mut ret = FxHashSet::default(); | |
807 | ret.reserve(6); // the minimum number of insertions | |
808 | // Target bindings. | |
809 | ret.insert((sym::target_os, Some(Symbol::intern(os)))); | |
810 | if let Some(ref fam) = sess.target.os_family { | |
811 | ret.insert((sym::target_family, Some(Symbol::intern(fam)))); | |
812 | if fam == "windows" { | |
813 | ret.insert((sym::windows, None)); | |
814 | } else if fam == "unix" { | |
815 | ret.insert((sym::unix, None)); | |
816 | } | |
817 | } | |
818 | ret.insert((sym::target_arch, Some(Symbol::intern(arch)))); | |
819 | ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str())))); | |
820 | ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz)))); | |
821 | ret.insert((sym::target_env, Some(Symbol::intern(env)))); | |
822 | ret.insert((sym::target_vendor, Some(Symbol::intern(vendor)))); | |
823 | if sess.target.has_elf_tls { | |
824 | ret.insert((sym::target_thread_local, None)); | |
825 | } | |
826 | for &(i, align) in &[ | |
827 | (8, layout.i8_align.abi), | |
828 | (16, layout.i16_align.abi), | |
829 | (32, layout.i32_align.abi), | |
830 | (64, layout.i64_align.abi), | |
831 | (128, layout.i128_align.abi), | |
832 | ] { | |
833 | if i >= min_atomic_width && i <= max_atomic_width { | |
834 | let mut insert_atomic = |s, align: Align| { | |
835 | ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s)))); | |
836 | if atomic_cas { | |
837 | ret.insert((sym::target_has_atomic, Some(Symbol::intern(s)))); | |
838 | } | |
839 | if align.bits() == i { | |
840 | ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s)))); | |
841 | } | |
842 | }; | |
843 | let s = i.to_string(); | |
844 | insert_atomic(&s, align); | |
845 | if s == wordsz { | |
846 | insert_atomic("ptr", layout.pointer_align.abi); | |
847 | } | |
848 | } | |
849 | } | |
850 | ||
851 | let panic_strategy = sess.panic_strategy(); | |
852 | ret.insert((sym::panic, Some(panic_strategy.desc_symbol()))); | |
853 | ||
854 | for s in sess.opts.debugging_opts.sanitizer { | |
855 | let symbol = Symbol::intern(&s.to_string()); | |
856 | ret.insert((sym::sanitize, Some(symbol))); | |
857 | } | |
858 | ||
859 | if sess.opts.debug_assertions { | |
860 | ret.insert((sym::debug_assertions, None)); | |
861 | } | |
862 | if sess.opts.crate_types.contains(&CrateType::ProcMacro) { | |
863 | ret.insert((sym::proc_macro, None)); | |
864 | } | |
865 | ret | |
866 | } | |
867 | ||
868 | /// Converts the crate `cfg!` configuration from `String` to `Symbol`. | |
869 | /// `rustc_interface::interface::Config` accepts this in the compiler configuration, | |
870 | /// but the symbol interner is not yet set up then, so we must convert it later. | |
871 | pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig { | |
872 | cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect() | |
873 | } | |
874 | ||
875 | pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig { | |
876 | // Combine the configuration requested by the session (command line) with | |
877 | // some default and generated configuration items. | |
878 | let default_cfg = default_configuration(sess); | |
879 | // If the user wants a test runner, then add the test cfg. | |
880 | if sess.opts.test { | |
881 | user_cfg.insert((sym::test, None)); | |
882 | } | |
883 | user_cfg.extend(default_cfg.iter().cloned()); | |
884 | user_cfg | |
885 | } | |
886 | ||
887 | pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target { | |
888 | let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok); | |
889 | let target = target_result.unwrap_or_else(|e| { | |
890 | early_error( | |
891 | opts.error_format, | |
892 | &format!( | |
893 | "Error loading target specification: {}. \ | |
894 | Use `--print target-list` for a list of built-in targets", | |
895 | e | |
896 | ), | |
897 | ) | |
898 | }); | |
899 | ||
900 | if !matches!(target.pointer_width, 16 | 32 | 64) { | |
901 | early_error( | |
902 | opts.error_format, | |
903 | &format!( | |
904 | "target specification was invalid: \ | |
905 | unrecognized target-pointer-width {}", | |
906 | target.pointer_width | |
907 | ), | |
908 | ) | |
909 | } | |
910 | ||
911 | target | |
912 | } | |
913 | ||
914 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
915 | pub enum OptionStability { | |
916 | Stable, | |
917 | Unstable, | |
918 | } | |
919 | ||
920 | pub struct RustcOptGroup { | |
921 | pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>, | |
922 | pub name: &'static str, | |
923 | pub stability: OptionStability, | |
924 | } | |
925 | ||
926 | impl RustcOptGroup { | |
927 | pub fn is_stable(&self) -> bool { | |
928 | self.stability == OptionStability::Stable | |
929 | } | |
930 | ||
931 | pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup | |
932 | where | |
933 | F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, | |
934 | { | |
935 | RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable } | |
936 | } | |
937 | ||
938 | pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup | |
939 | where | |
940 | F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, | |
941 | { | |
942 | RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable } | |
943 | } | |
944 | } | |
945 | ||
946 | // The `opt` local module holds wrappers around the `getopts` API that | |
947 | // adds extra rustc-specific metadata to each option; such metadata | |
948 | // is exposed by . The public | |
949 | // functions below ending with `_u` are the functions that return | |
950 | // *unstable* options, i.e., options that are only enabled when the | |
951 | // user also passes the `-Z unstable-options` debugging flag. | |
952 | mod opt { | |
953 | // The `fn flag*` etc below are written so that we can use them | |
954 | // in the future; do not warn about them not being used right now. | |
955 | #![allow(dead_code)] | |
956 | ||
957 | use super::RustcOptGroup; | |
958 | ||
959 | pub type R = RustcOptGroup; | |
960 | pub type S = &'static str; | |
961 | ||
962 | fn stable<F>(name: S, f: F) -> R | |
963 | where | |
964 | F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, | |
965 | { | |
966 | RustcOptGroup::stable(name, f) | |
967 | } | |
968 | ||
969 | fn unstable<F>(name: S, f: F) -> R | |
970 | where | |
971 | F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, | |
972 | { | |
973 | RustcOptGroup::unstable(name, f) | |
974 | } | |
975 | ||
976 | fn longer(a: S, b: S) -> S { | |
977 | if a.len() > b.len() { a } else { b } | |
978 | } | |
979 | ||
980 | pub fn opt_s(a: S, b: S, c: S, d: S) -> R { | |
981 | stable(longer(a, b), move |opts| opts.optopt(a, b, c, d)) | |
982 | } | |
983 | pub fn multi_s(a: S, b: S, c: S, d: S) -> R { | |
984 | stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) | |
985 | } | |
986 | pub fn flag_s(a: S, b: S, c: S) -> R { | |
987 | stable(longer(a, b), move |opts| opts.optflag(a, b, c)) | |
988 | } | |
989 | pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R { | |
990 | stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d)) | |
991 | } | |
992 | pub fn flagmulti_s(a: S, b: S, c: S) -> R { | |
993 | stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c)) | |
994 | } | |
995 | ||
996 | pub fn opt(a: S, b: S, c: S, d: S) -> R { | |
997 | unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d)) | |
998 | } | |
999 | pub fn multi(a: S, b: S, c: S, d: S) -> R { | |
1000 | unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) | |
1001 | } | |
1002 | pub fn flag(a: S, b: S, c: S) -> R { | |
1003 | unstable(longer(a, b), move |opts| opts.optflag(a, b, c)) | |
1004 | } | |
1005 | pub fn flagopt(a: S, b: S, c: S, d: S) -> R { | |
1006 | unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d)) | |
1007 | } | |
1008 | pub fn flagmulti(a: S, b: S, c: S) -> R { | |
1009 | unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c)) | |
1010 | } | |
1011 | } | |
1012 | ||
1013 | /// Returns the "short" subset of the rustc command line options, | |
1014 | /// including metadata for each option, such as whether the option is | |
1015 | /// part of the stable long-term interface for rustc. | |
1016 | pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { | |
1017 | vec![ | |
1018 | opt::flag_s("h", "help", "Display this message"), | |
1019 | opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"), | |
1020 | opt::multi_s( | |
1021 | "L", | |
1022 | "", | |
1023 | "Add a directory to the library search path. The | |
1024 | optional KIND can be one of dependency, crate, native, | |
1025 | framework, or all (the default).", | |
1026 | "[KIND=]PATH", | |
1027 | ), | |
1028 | opt::multi_s( | |
1029 | "l", | |
1030 | "", | |
1031 | "Link the generated crate(s) to the specified native | |
1032 | library NAME. The optional KIND can be one of | |
1033 | static, framework, or dylib (the default).", | |
1034 | "[KIND=]NAME", | |
1035 | ), | |
1036 | make_crate_type_option(), | |
1037 | opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"), | |
1038 | opt::opt_s( | |
1039 | "", | |
1040 | "edition", | |
1041 | "Specify which edition of the compiler to use when compiling code.", | |
1042 | EDITION_NAME_LIST, | |
1043 | ), | |
1044 | opt::multi_s( | |
1045 | "", | |
1046 | "emit", | |
1047 | "Comma separated list of types of output for \ | |
1048 | the compiler to emit", | |
1049 | "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]", | |
1050 | ), | |
1051 | opt::multi_s( | |
1052 | "", | |
1053 | "print", | |
1054 | "Compiler information to print on stdout", | |
1055 | "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\ | |
1056 | target-cpus|target-features|relocation-models|\ | |
1057 | code-models|tls-models|target-spec-json|native-static-libs]", | |
1058 | ), | |
1059 | opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), | |
1060 | opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), | |
1061 | opt::opt_s("o", "", "Write output to <filename>", "FILENAME"), | |
1062 | opt::opt_s( | |
1063 | "", | |
1064 | "out-dir", | |
1065 | "Write output to compiler-chosen filename \ | |
1066 | in <dir>", | |
1067 | "DIR", | |
1068 | ), | |
1069 | opt::opt_s( | |
1070 | "", | |
1071 | "explain", | |
1072 | "Provide a detailed explanation of an error \ | |
1073 | message", | |
1074 | "OPT", | |
1075 | ), | |
1076 | opt::flag_s("", "test", "Build a test harness"), | |
1077 | opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"), | |
1078 | opt::multi_s("W", "warn", "Set lint warnings", "OPT"), | |
1079 | opt::multi_s("A", "allow", "Set lint allowed", "OPT"), | |
1080 | opt::multi_s("D", "deny", "Set lint denied", "OPT"), | |
1081 | opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"), | |
1082 | opt::multi_s( | |
1083 | "", | |
1084 | "cap-lints", | |
1085 | "Set the most restrictive lint level. \ | |
1086 | More restrictive lints are capped at this \ | |
1087 | level", | |
1088 | "LEVEL", | |
1089 | ), | |
1090 | opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"), | |
1091 | opt::flag_s("V", "version", "Print version info and exit"), | |
1092 | opt::flag_s("v", "verbose", "Use verbose output"), | |
1093 | ] | |
1094 | } | |
1095 | ||
1096 | /// Returns all rustc command line options, including metadata for | |
1097 | /// each option, such as whether the option is part of the stable | |
1098 | /// long-term interface for rustc. | |
1099 | pub fn rustc_optgroups() -> Vec<RustcOptGroup> { | |
1100 | let mut opts = rustc_short_optgroups(); | |
1101 | opts.extend(vec![ | |
1102 | opt::multi_s( | |
1103 | "", | |
1104 | "extern", | |
1105 | "Specify where an external rust library is located", | |
1106 | "NAME[=PATH]", | |
1107 | ), | |
1108 | opt::opt_s("", "sysroot", "Override the system root", "PATH"), | |
1109 | opt::multi("Z", "", "Set internal debugging options", "FLAG"), | |
1110 | opt::opt_s( | |
1111 | "", | |
1112 | "error-format", | |
1113 | "How errors and other messages are produced", | |
1114 | "human|json|short", | |
1115 | ), | |
1116 | opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"), | |
1117 | opt::opt_s( | |
1118 | "", | |
1119 | "color", | |
1120 | "Configure coloring of output: | |
1121 | auto = colorize, if output goes to a tty (default); | |
1122 | always = always colorize output; | |
1123 | never = never colorize output", | |
1124 | "auto|always|never", | |
1125 | ), | |
1126 | opt::opt( | |
1127 | "", | |
1128 | "pretty", | |
1129 | "Pretty-print the input instead of compiling; | |
1130 | valid types are: `normal` (un-annotated source), | |
1131 | `expanded` (crates expanded), or | |
1132 | `expanded,identified` (fully parenthesized, AST nodes with IDs).", | |
1133 | "TYPE", | |
1134 | ), | |
1135 | opt::multi_s( | |
1136 | "", | |
1137 | "remap-path-prefix", | |
1138 | "Remap source names in all output (compiler messages and output files)", | |
1139 | "FROM=TO", | |
1140 | ), | |
1141 | ]); | |
1142 | opts | |
1143 | } | |
1144 | ||
1145 | pub fn get_cmd_lint_options( | |
1146 | matches: &getopts::Matches, | |
1147 | error_format: ErrorOutputType, | |
1148 | ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) { | |
1149 | let mut lint_opts_with_position = vec![]; | |
1150 | let mut describe_lints = false; | |
1151 | ||
1152 | for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] { | |
1153 | for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) { | |
1154 | let arg_pos = if let lint::Forbid = level { | |
1155 | // HACK: forbid is always specified last, so it can't be overridden. | |
1156 | // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is | |
1157 | // fixed and `forbid` works as expected. | |
1158 | usize::MAX | |
1159 | } else { | |
1160 | passed_arg_pos | |
1161 | }; | |
1162 | if lint_name == "help" { | |
1163 | describe_lints = true; | |
1164 | } else { | |
1165 | lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level)); | |
1166 | } | |
1167 | } | |
1168 | } | |
1169 | ||
1170 | lint_opts_with_position.sort_by_key(|x| x.0); | |
1171 | let lint_opts = lint_opts_with_position | |
1172 | .iter() | |
1173 | .cloned() | |
1174 | .map(|(_, lint_name, level)| (lint_name, level)) | |
1175 | .collect(); | |
1176 | ||
1177 | let lint_cap = matches.opt_str("cap-lints").map(|cap| { | |
1178 | lint::Level::from_str(&cap) | |
1179 | .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap))) | |
1180 | }); | |
1181 | (lint_opts, describe_lints, lint_cap) | |
1182 | } | |
1183 | ||
1184 | /// Parses the `--color` flag. | |
1185 | pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { | |
1186 | match matches.opt_str("color").as_ref().map(|s| &s[..]) { | |
1187 | Some("auto") => ColorConfig::Auto, | |
1188 | Some("always") => ColorConfig::Always, | |
1189 | Some("never") => ColorConfig::Never, | |
1190 | ||
1191 | None => ColorConfig::Auto, | |
1192 | ||
1193 | Some(arg) => early_error( | |
1194 | ErrorOutputType::default(), | |
1195 | &format!( | |
1196 | "argument for `--color` must be auto, \ | |
1197 | always or never (instead was `{}`)", | |
1198 | arg | |
1199 | ), | |
1200 | ), | |
1201 | } | |
1202 | } | |
1203 | ||
1204 | /// Parse the `--json` flag. | |
1205 | /// | |
1206 | /// The first value returned is how to render JSON diagnostics, and the second | |
1207 | /// is whether or not artifact notifications are enabled. | |
1208 | pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) { | |
1209 | let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType = | |
1210 | HumanReadableErrorType::Default; | |
1211 | let mut json_color = ColorConfig::Never; | |
1212 | let mut json_artifact_notifications = false; | |
1213 | for option in matches.opt_strs("json") { | |
1214 | // For now conservatively forbid `--color` with `--json` since `--json` | |
1215 | // won't actually be emitting any colors and anything colorized is | |
1216 | // embedded in a diagnostic message anyway. | |
1217 | if matches.opt_str("color").is_some() { | |
1218 | early_error( | |
1219 | ErrorOutputType::default(), | |
1220 | "cannot specify the `--color` option with `--json`", | |
1221 | ); | |
1222 | } | |
1223 | ||
1224 | for sub_option in option.split(',') { | |
1225 | match sub_option { | |
1226 | "diagnostic-short" => json_rendered = HumanReadableErrorType::Short, | |
1227 | "diagnostic-rendered-ansi" => json_color = ColorConfig::Always, | |
1228 | "artifacts" => json_artifact_notifications = true, | |
1229 | s => early_error( | |
1230 | ErrorOutputType::default(), | |
1231 | &format!("unknown `--json` option `{}`", s), | |
1232 | ), | |
1233 | } | |
1234 | } | |
1235 | } | |
1236 | (json_rendered(json_color), json_artifact_notifications) | |
1237 | } | |
1238 | ||
1239 | /// Parses the `--error-format` flag. | |
1240 | pub fn parse_error_format( | |
1241 | matches: &getopts::Matches, | |
1242 | color: ColorConfig, | |
1243 | json_rendered: HumanReadableErrorType, | |
1244 | ) -> ErrorOutputType { | |
1245 | // We need the `opts_present` check because the driver will send us Matches | |
1246 | // with only stable options if no unstable options are used. Since error-format | |
1247 | // is unstable, it will not be present. We have to use `opts_present` not | |
1248 | // `opt_present` because the latter will panic. | |
1249 | let error_format = if matches.opts_present(&["error-format".to_owned()]) { | |
1250 | match matches.opt_str("error-format").as_ref().map(|s| &s[..]) { | |
1251 | None | Some("human") => { | |
1252 | ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)) | |
1253 | } | |
1254 | Some("human-annotate-rs") => { | |
1255 | ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color)) | |
1256 | } | |
1257 | Some("json") => ErrorOutputType::Json { pretty: false, json_rendered }, | |
1258 | Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered }, | |
1259 | Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)), | |
1260 | ||
1261 | Some(arg) => early_error( | |
1262 | ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), | |
1263 | &format!( | |
1264 | "argument for `--error-format` must be `human`, `json` or \ | |
1265 | `short` (instead was `{}`)", | |
1266 | arg | |
1267 | ), | |
1268 | ), | |
1269 | } | |
1270 | } else { | |
1271 | ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)) | |
1272 | }; | |
1273 | ||
1274 | match error_format { | |
1275 | ErrorOutputType::Json { .. } => {} | |
1276 | ||
1277 | // Conservatively require that the `--json` argument is coupled with | |
1278 | // `--error-format=json`. This means that `--json` is specified we | |
1279 | // should actually be emitting JSON blobs. | |
1280 | _ if !matches.opt_strs("json").is_empty() => { | |
1281 | early_error( | |
1282 | ErrorOutputType::default(), | |
1283 | "using `--json` requires also using `--error-format=json`", | |
1284 | ); | |
1285 | } | |
1286 | ||
1287 | _ => {} | |
1288 | } | |
1289 | ||
1290 | error_format | |
1291 | } | |
1292 | ||
1293 | fn parse_crate_edition(matches: &getopts::Matches) -> Edition { | |
1294 | let edition = match matches.opt_str("edition") { | |
1295 | Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| { | |
1296 | early_error( | |
1297 | ErrorOutputType::default(), | |
1298 | &format!( | |
1299 | "argument for `--edition` must be one of: \ | |
1300 | {}. (instead was `{}`)", | |
1301 | EDITION_NAME_LIST, arg | |
1302 | ), | |
1303 | ) | |
1304 | }), | |
1305 | None => DEFAULT_EDITION, | |
1306 | }; | |
1307 | ||
1308 | if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) { | |
1309 | early_error( | |
1310 | ErrorOutputType::default(), | |
1311 | &format!( | |
1312 | "edition {} is unstable and only available with -Z unstable-options.", | |
1313 | edition, | |
1314 | ), | |
1315 | ) | |
1316 | } | |
1317 | ||
1318 | edition | |
1319 | } | |
1320 | ||
1321 | fn check_debug_option_stability( | |
1322 | debugging_opts: &DebuggingOptions, | |
1323 | error_format: ErrorOutputType, | |
1324 | json_rendered: HumanReadableErrorType, | |
1325 | ) { | |
1326 | if !debugging_opts.unstable_options { | |
1327 | if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format { | |
1328 | early_error( | |
1329 | ErrorOutputType::Json { pretty: false, json_rendered }, | |
1330 | "`--error-format=pretty-json` is unstable", | |
1331 | ); | |
1332 | } | |
1333 | if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) = | |
1334 | error_format | |
1335 | { | |
1336 | early_error( | |
1337 | ErrorOutputType::Json { pretty: false, json_rendered }, | |
1338 | "`--error-format=human-annotate-rs` is unstable", | |
1339 | ); | |
1340 | } | |
1341 | } | |
1342 | } | |
1343 | ||
1344 | fn parse_output_types( | |
1345 | debugging_opts: &DebuggingOptions, | |
1346 | matches: &getopts::Matches, | |
1347 | error_format: ErrorOutputType, | |
1348 | ) -> OutputTypes { | |
1349 | let mut output_types = BTreeMap::new(); | |
1350 | if !debugging_opts.parse_only { | |
1351 | for list in matches.opt_strs("emit") { | |
1352 | for output_type in list.split(',') { | |
1353 | let (shorthand, path) = match output_type.split_once('=') { | |
1354 | None => (output_type, None), | |
1355 | Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))), | |
1356 | }; | |
1357 | let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { | |
1358 | early_error( | |
1359 | error_format, | |
1360 | &format!( | |
1361 | "unknown emission type: `{}` - expected one of: {}", | |
1362 | shorthand, | |
1363 | OutputType::shorthands_display(), | |
1364 | ), | |
1365 | ) | |
1366 | }); | |
1367 | output_types.insert(output_type, path); | |
1368 | } | |
1369 | } | |
1370 | }; | |
1371 | if output_types.is_empty() { | |
1372 | output_types.insert(OutputType::Exe, None); | |
1373 | } | |
1374 | OutputTypes(output_types) | |
1375 | } | |
1376 | ||
1377 | fn should_override_cgus_and_disable_thinlto( | |
1378 | output_types: &OutputTypes, | |
1379 | matches: &getopts::Matches, | |
1380 | error_format: ErrorOutputType, | |
1381 | mut codegen_units: Option<usize>, | |
1382 | ) -> (bool, Option<usize>) { | |
1383 | let mut disable_thinlto = false; | |
1384 | // Issue #30063: if user requests LLVM-related output to one | |
1385 | // particular path, disable codegen-units. | |
1386 | let incompatible: Vec<_> = output_types | |
1387 | .0 | |
1388 | .iter() | |
1389 | .map(|ot_path| ot_path.0) | |
1390 | .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file()) | |
1391 | .map(|ot| ot.shorthand()) | |
1392 | .collect(); | |
1393 | if !incompatible.is_empty() { | |
1394 | match codegen_units { | |
1395 | Some(n) if n > 1 => { | |
1396 | if matches.opt_present("o") { | |
1397 | for ot in &incompatible { | |
1398 | early_warn( | |
1399 | error_format, | |
1400 | &format!( | |
1401 | "`--emit={}` with `-o` incompatible with \ | |
1402 | `-C codegen-units=N` for N > 1", | |
1403 | ot | |
1404 | ), | |
1405 | ); | |
1406 | } | |
1407 | early_warn(error_format, "resetting to default -C codegen-units=1"); | |
1408 | codegen_units = Some(1); | |
1409 | disable_thinlto = true; | |
1410 | } | |
1411 | } | |
1412 | _ => { | |
1413 | codegen_units = Some(1); | |
1414 | disable_thinlto = true; | |
1415 | } | |
1416 | } | |
1417 | } | |
1418 | ||
1419 | if codegen_units == Some(0) { | |
1420 | early_error(error_format, "value for codegen units must be a positive non-zero integer"); | |
1421 | } | |
1422 | ||
1423 | (disable_thinlto, codegen_units) | |
1424 | } | |
1425 | ||
1426 | fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) { | |
1427 | if debugging_opts.threads == 0 { | |
1428 | early_error(error_format, "value for threads must be a positive non-zero integer"); | |
1429 | } | |
1430 | ||
1431 | if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() { | |
1432 | early_error(error_format, "optimization fuel is incompatible with multiple threads"); | |
1433 | } | |
1434 | } | |
1435 | ||
1436 | fn collect_print_requests( | |
1437 | cg: &mut CodegenOptions, | |
1438 | dopts: &mut DebuggingOptions, | |
1439 | matches: &getopts::Matches, | |
1440 | error_format: ErrorOutputType, | |
1441 | ) -> Vec<PrintRequest> { | |
1442 | let mut prints = Vec::<PrintRequest>::new(); | |
1443 | if cg.target_cpu.as_ref().map_or(false, |s| s == "help") { | |
1444 | prints.push(PrintRequest::TargetCPUs); | |
1445 | cg.target_cpu = None; | |
1446 | }; | |
1447 | if cg.target_feature == "help" { | |
1448 | prints.push(PrintRequest::TargetFeatures); | |
1449 | cg.target_feature = String::new(); | |
1450 | } | |
1451 | ||
1452 | prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s { | |
1453 | "crate-name" => PrintRequest::CrateName, | |
1454 | "file-names" => PrintRequest::FileNames, | |
1455 | "sysroot" => PrintRequest::Sysroot, | |
1456 | "target-libdir" => PrintRequest::TargetLibdir, | |
1457 | "cfg" => PrintRequest::Cfg, | |
1458 | "target-list" => PrintRequest::TargetList, | |
1459 | "target-cpus" => PrintRequest::TargetCPUs, | |
1460 | "target-features" => PrintRequest::TargetFeatures, | |
1461 | "relocation-models" => PrintRequest::RelocationModels, | |
1462 | "code-models" => PrintRequest::CodeModels, | |
1463 | "tls-models" => PrintRequest::TlsModels, | |
1464 | "native-static-libs" => PrintRequest::NativeStaticLibs, | |
1465 | "target-spec-json" => { | |
1466 | if dopts.unstable_options { | |
1467 | PrintRequest::TargetSpec | |
1468 | } else { | |
1469 | early_error( | |
1470 | error_format, | |
1471 | "the `-Z unstable-options` flag must also be passed to \ | |
1472 | enable the target-spec-json print option", | |
1473 | ); | |
1474 | } | |
1475 | } | |
1476 | req => early_error(error_format, &format!("unknown print request `{}`", req)), | |
1477 | })); | |
1478 | ||
1479 | prints | |
1480 | } | |
1481 | ||
1482 | fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple { | |
1483 | match matches.opt_str("target") { | |
1484 | Some(target) if target.ends_with(".json") => { | |
1485 | let path = Path::new(&target); | |
1486 | TargetTriple::from_path(&path).unwrap_or_else(|_| { | |
1487 | early_error(error_format, &format!("target file {:?} does not exist", path)) | |
1488 | }) | |
1489 | } | |
1490 | Some(target) => TargetTriple::from_alias(target), | |
1491 | _ => TargetTriple::from_triple(host_triple()), | |
1492 | } | |
1493 | } | |
1494 | ||
1495 | fn parse_opt_level( | |
1496 | matches: &getopts::Matches, | |
1497 | cg: &CodegenOptions, | |
1498 | error_format: ErrorOutputType, | |
1499 | ) -> OptLevel { | |
1500 | // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able | |
1501 | // to use them interchangeably. However, because they're technically different flags, | |
1502 | // we need to work out manually which should take precedence if both are supplied (i.e. | |
1503 | // the rightmost flag). We do this by finding the (rightmost) position of both flags and | |
1504 | // comparing them. Note that if a flag is not found, its position will be `None`, which | |
1505 | // always compared less than `Some(_)`. | |
1506 | let max_o = matches.opt_positions("O").into_iter().max(); | |
1507 | let max_c = matches | |
1508 | .opt_strs_pos("C") | |
1509 | .into_iter() | |
1510 | .flat_map(|(i, s)| { | |
1511 | // NB: This can match a string without `=`. | |
1512 | if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None } | |
1513 | }) | |
1514 | .max(); | |
1515 | if max_o > max_c { | |
1516 | OptLevel::Default | |
1517 | } else { | |
1518 | match cg.opt_level.as_ref() { | |
1519 | "0" => OptLevel::No, | |
1520 | "1" => OptLevel::Less, | |
1521 | "2" => OptLevel::Default, | |
1522 | "3" => OptLevel::Aggressive, | |
1523 | "s" => OptLevel::Size, | |
1524 | "z" => OptLevel::SizeMin, | |
1525 | arg => { | |
1526 | early_error( | |
1527 | error_format, | |
1528 | &format!( | |
1529 | "optimization level needs to be \ | |
1530 | between 0-3, s or z (instead was `{}`)", | |
1531 | arg | |
1532 | ), | |
1533 | ); | |
1534 | } | |
1535 | } | |
1536 | } | |
1537 | } | |
1538 | ||
1539 | fn select_debuginfo( | |
1540 | matches: &getopts::Matches, | |
1541 | cg: &CodegenOptions, | |
1542 | error_format: ErrorOutputType, | |
1543 | ) -> DebugInfo { | |
1544 | let max_g = matches.opt_positions("g").into_iter().max(); | |
1545 | let max_c = matches | |
1546 | .opt_strs_pos("C") | |
1547 | .into_iter() | |
1548 | .flat_map(|(i, s)| { | |
1549 | // NB: This can match a string without `=`. | |
1550 | if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None } | |
1551 | }) | |
1552 | .max(); | |
1553 | if max_g > max_c { | |
1554 | DebugInfo::Full | |
1555 | } else { | |
1556 | match cg.debuginfo { | |
1557 | 0 => DebugInfo::None, | |
1558 | 1 => DebugInfo::Limited, | |
1559 | 2 => DebugInfo::Full, | |
1560 | arg => { | |
1561 | early_error( | |
1562 | error_format, | |
1563 | &format!( | |
1564 | "debug info level needs to be between \ | |
1565 | 0-2 (instead was `{}`)", | |
1566 | arg | |
1567 | ), | |
1568 | ); | |
1569 | } | |
1570 | } | |
1571 | } | |
1572 | } | |
1573 | ||
1574 | fn parse_libs( | |
1575 | matches: &getopts::Matches, | |
1576 | error_format: ErrorOutputType, | |
1577 | ) -> Vec<(String, Option<String>, NativeLibKind)> { | |
1578 | matches | |
1579 | .opt_strs("l") | |
1580 | .into_iter() | |
1581 | .map(|s| { | |
1582 | // Parse string of the form "[KIND=]lib[:new_name]", | |
1583 | // where KIND is one of "dylib", "framework", "static". | |
1584 | let (name, kind) = match s.split_once('=') { | |
1585 | None => (s, NativeLibKind::Unspecified), | |
1586 | Some((kind, name)) => { | |
1587 | let kind = match kind { | |
1588 | "dylib" => NativeLibKind::Dylib, | |
1589 | "framework" => NativeLibKind::Framework, | |
1590 | "static" => NativeLibKind::StaticBundle, | |
1591 | "static-nobundle" => NativeLibKind::StaticNoBundle, | |
1592 | s => { | |
1593 | early_error( | |
1594 | error_format, | |
1595 | &format!( | |
1596 | "unknown library kind `{}`, expected \ | |
1597 | one of dylib, framework, or static", | |
1598 | s | |
1599 | ), | |
1600 | ); | |
1601 | } | |
1602 | }; | |
1603 | (name.to_string(), kind) | |
1604 | } | |
1605 | }; | |
1606 | if kind == NativeLibKind::StaticNoBundle | |
1607 | && !nightly_options::match_is_nightly_build(matches) | |
1608 | { | |
1609 | early_error( | |
1610 | error_format, | |
1611 | "the library kind 'static-nobundle' is only \ | |
1612 | accepted on the nightly compiler", | |
1613 | ); | |
1614 | } | |
1615 | let (name, new_name) = match name.split_once(':') { | |
1616 | None => (name, None), | |
1617 | Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), | |
1618 | }; | |
1619 | (name, new_name, kind) | |
1620 | }) | |
1621 | .collect() | |
1622 | } | |
1623 | ||
1624 | fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode { | |
1625 | match dopts.borrowck.as_ref() { | |
1626 | "migrate" => BorrowckMode::Migrate, | |
1627 | "mir" => BorrowckMode::Mir, | |
1628 | m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)), | |
1629 | } | |
1630 | } | |
1631 | ||
1632 | pub fn parse_externs( | |
1633 | matches: &getopts::Matches, | |
1634 | debugging_opts: &DebuggingOptions, | |
1635 | error_format: ErrorOutputType, | |
1636 | ) -> Externs { | |
1637 | let is_unstable_enabled = debugging_opts.unstable_options; | |
1638 | let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new(); | |
1639 | for arg in matches.opt_strs("extern") { | |
1640 | let (name, path) = match arg.split_once('=') { | |
1641 | None => (arg, None), | |
1642 | Some((name, path)) => (name.to_string(), Some(Path::new(path))), | |
1643 | }; | |
1644 | let (options, name) = match name.split_once(':') { | |
1645 | None => (None, name), | |
1646 | Some((opts, name)) => (Some(opts), name.to_string()), | |
1647 | }; | |
1648 | ||
1649 | let path = path.map(|p| CanonicalizedPath::new(p)); | |
1650 | ||
1651 | let entry = externs.entry(name.to_owned()); | |
1652 | ||
1653 | use std::collections::btree_map::Entry; | |
1654 | ||
1655 | let entry = if let Some(path) = path { | |
1656 | // --extern prelude_name=some_file.rlib | |
1657 | match entry { | |
1658 | Entry::Vacant(vacant) => { | |
1659 | let files = BTreeSet::from_iter(iter::once(path)); | |
1660 | vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files))) | |
1661 | } | |
1662 | Entry::Occupied(occupied) => { | |
1663 | let ext_ent = occupied.into_mut(); | |
1664 | match ext_ent { | |
1665 | ExternEntry { location: ExternLocation::ExactPaths(files), .. } => { | |
1666 | files.insert(path); | |
1667 | } | |
1668 | ExternEntry { | |
1669 | location: location @ ExternLocation::FoundInLibrarySearchDirectories, | |
1670 | .. | |
1671 | } => { | |
1672 | // Exact paths take precedence over search directories. | |
1673 | let files = BTreeSet::from_iter(iter::once(path)); | |
1674 | *location = ExternLocation::ExactPaths(files); | |
1675 | } | |
1676 | } | |
1677 | ext_ent | |
1678 | } | |
1679 | } | |
1680 | } else { | |
1681 | // --extern prelude_name | |
1682 | match entry { | |
1683 | Entry::Vacant(vacant) => { | |
1684 | vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories)) | |
1685 | } | |
1686 | Entry::Occupied(occupied) => { | |
1687 | // Ignore if already specified. | |
1688 | occupied.into_mut() | |
1689 | } | |
1690 | } | |
1691 | }; | |
1692 | ||
1693 | let mut is_private_dep = false; | |
1694 | let mut add_prelude = true; | |
1695 | if let Some(opts) = options { | |
1696 | if !is_unstable_enabled { | |
1697 | early_error( | |
1698 | error_format, | |
1699 | "the `-Z unstable-options` flag must also be passed to \ | |
1700 | enable `--extern options", | |
1701 | ); | |
1702 | } | |
1703 | for opt in opts.split(',') { | |
1704 | match opt { | |
1705 | "priv" => is_private_dep = true, | |
1706 | "noprelude" => { | |
1707 | if let ExternLocation::ExactPaths(_) = &entry.location { | |
1708 | add_prelude = false; | |
1709 | } else { | |
1710 | early_error( | |
1711 | error_format, | |
1712 | "the `noprelude` --extern option requires a file path", | |
1713 | ); | |
1714 | } | |
1715 | } | |
1716 | _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)), | |
1717 | } | |
1718 | } | |
1719 | } | |
1720 | ||
1721 | // Crates start out being not private, and go to being private `priv` | |
1722 | // is specified. | |
1723 | entry.is_private_dep |= is_private_dep; | |
1724 | // If any flag is missing `noprelude`, then add to the prelude. | |
1725 | entry.add_prelude |= add_prelude; | |
1726 | } | |
1727 | Externs(externs) | |
1728 | } | |
1729 | ||
1730 | fn parse_remap_path_prefix( | |
1731 | matches: &getopts::Matches, | |
1732 | error_format: ErrorOutputType, | |
1733 | ) -> Vec<(PathBuf, PathBuf)> { | |
1734 | matches | |
1735 | .opt_strs("remap-path-prefix") | |
1736 | .into_iter() | |
1737 | .map(|remap| match remap.rsplit_once('=') { | |
1738 | None => early_error( | |
1739 | error_format, | |
1740 | "--remap-path-prefix must contain '=' between FROM and TO", | |
1741 | ), | |
1742 | Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), | |
1743 | }) | |
1744 | .collect() | |
1745 | } | |
1746 | ||
1747 | pub fn build_session_options(matches: &getopts::Matches) -> Options { | |
1748 | let color = parse_color(matches); | |
1749 | ||
1750 | let edition = parse_crate_edition(matches); | |
1751 | ||
1752 | let (json_rendered, json_artifact_notifications) = parse_json(matches); | |
1753 | ||
1754 | let error_format = parse_error_format(matches, color, json_rendered); | |
1755 | ||
1756 | let unparsed_crate_types = matches.opt_strs("crate-type"); | |
1757 | let crate_types = parse_crate_types_from_list(unparsed_crate_types) | |
1758 | .unwrap_or_else(|e| early_error(error_format, &e[..])); | |
1759 | ||
1760 | let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); | |
1761 | ||
1762 | let mut debugging_opts = build_debugging_options(matches, error_format); | |
1763 | check_debug_option_stability(&debugging_opts, error_format, json_rendered); | |
1764 | ||
1765 | let output_types = parse_output_types(&debugging_opts, matches, error_format); | |
1766 | ||
1767 | let mut cg = build_codegen_options(matches, error_format); | |
1768 | let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto( | |
1769 | &output_types, | |
1770 | matches, | |
1771 | error_format, | |
1772 | cg.codegen_units, | |
1773 | ); | |
1774 | ||
1775 | check_thread_count(&debugging_opts, error_format); | |
1776 | ||
1777 | let incremental = cg.incremental.as_ref().map(PathBuf::from); | |
1778 | ||
1779 | if debugging_opts.profile && incremental.is_some() { | |
1780 | early_error( | |
1781 | error_format, | |
1782 | "can't instrument with gcov profiling when compiling incrementally", | |
1783 | ); | |
1784 | } | |
1785 | if debugging_opts.profile { | |
1786 | match codegen_units { | |
1787 | Some(1) => {} | |
1788 | None => codegen_units = Some(1), | |
1789 | Some(_) => early_error( | |
1790 | error_format, | |
1791 | "can't instrument with gcov profiling with multiple codegen units", | |
1792 | ), | |
1793 | } | |
1794 | } | |
1795 | ||
1796 | if cg.profile_generate.enabled() && cg.profile_use.is_some() { | |
1797 | early_error( | |
1798 | error_format, | |
1799 | "options `-C profile-generate` and `-C profile-use` are exclusive", | |
1800 | ); | |
1801 | } | |
1802 | ||
1803 | if debugging_opts.instrument_coverage { | |
1804 | if cg.profile_generate.enabled() || cg.profile_use.is_some() { | |
1805 | early_error( | |
1806 | error_format, | |
1807 | "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \ | |
1808 | or `-C profile-generate`", | |
1809 | ); | |
1810 | } | |
1811 | ||
1812 | // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent | |
1813 | // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over | |
1814 | // multiple runs, including some changes to source code; so mangled names must be consistent | |
1815 | // across compilations. | |
1816 | match debugging_opts.symbol_mangling_version { | |
1817 | None => { | |
1818 | debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0); | |
1819 | } | |
1820 | Some(SymbolManglingVersion::Legacy) => { | |
1821 | early_warn( | |
1822 | error_format, | |
1823 | "-Z instrument-coverage requires symbol mangling version `v0`, \ | |
1824 | but `-Z symbol-mangling-version=legacy` was specified", | |
1825 | ); | |
1826 | } | |
1827 | Some(SymbolManglingVersion::V0) => {} | |
1828 | } | |
1829 | ||
1830 | if debugging_opts.mir_opt_level > 1 { | |
1831 | // Functions inlined during MIR transform can, at best, make it impossible to | |
1832 | // effectively cover inlined functions, and, at worst, break coverage map generation | |
1833 | // during LLVM codegen. For example, function counter IDs are only unique within a | |
1834 | // function. Inlining after these counters are injected can produce duplicate counters, | |
1835 | // resulting in an invalid coverage map (and ICE); so this option combination is not | |
1836 | // allowed. | |
1837 | early_warn( | |
1838 | error_format, | |
1839 | &format!( | |
1840 | "`-Z mir-opt-level={}` (or any level > 1) enables function inlining, which \ | |
1841 | is incompatible with `-Z instrument-coverage`. Inlining will be disabled.", | |
1842 | debugging_opts.mir_opt_level, | |
1843 | ), | |
1844 | ); | |
1845 | } | |
1846 | } | |
1847 | ||
1848 | if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { | |
1849 | debugging_opts.graphviz_font = graphviz_font; | |
1850 | } | |
1851 | ||
1852 | if !cg.embed_bitcode { | |
1853 | match cg.lto { | |
1854 | LtoCli::No | LtoCli::Unspecified => {} | |
1855 | LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error( | |
1856 | error_format, | |
1857 | "options `-C embed-bitcode=no` and `-C lto` are incompatible", | |
1858 | ), | |
1859 | } | |
1860 | } | |
1861 | ||
1862 | let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format); | |
1863 | ||
1864 | let cg = cg; | |
1865 | ||
1866 | let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); | |
1867 | let target_triple = parse_target_triple(matches, error_format); | |
1868 | let opt_level = parse_opt_level(matches, &cg, error_format); | |
1869 | // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able | |
1870 | // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`) | |
1871 | // for more details. | |
1872 | let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No); | |
1873 | let debuginfo = select_debuginfo(matches, &cg, error_format); | |
1874 | ||
1875 | let mut search_paths = vec![]; | |
1876 | for s in &matches.opt_strs("L") { | |
1877 | search_paths.push(SearchPath::from_cli_opt(&s[..], error_format)); | |
1878 | } | |
1879 | ||
1880 | let libs = parse_libs(matches, error_format); | |
1881 | ||
1882 | let test = matches.opt_present("test"); | |
1883 | ||
1884 | let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format); | |
1885 | ||
1886 | if !cg.remark.is_empty() && debuginfo == DebugInfo::None { | |
1887 | early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations"); | |
1888 | } | |
1889 | ||
1890 | let externs = parse_externs(matches, &debugging_opts, error_format); | |
1891 | ||
1892 | let crate_name = matches.opt_str("crate-name"); | |
1893 | ||
1894 | let remap_path_prefix = parse_remap_path_prefix(matches, error_format); | |
1895 | ||
1896 | let pretty = parse_pretty(matches, &debugging_opts, error_format); | |
1897 | ||
1898 | if !debugging_opts.unstable_options | |
1899 | && !target_triple.triple().contains("apple") | |
1900 | && cg.split_debuginfo.is_some() | |
1901 | { | |
1902 | { | |
1903 | early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform"); | |
1904 | } | |
1905 | } | |
1906 | ||
1907 | Options { | |
1908 | crate_types, | |
1909 | optimize: opt_level, | |
1910 | debuginfo, | |
1911 | lint_opts, | |
1912 | lint_cap, | |
1913 | describe_lints, | |
1914 | output_types, | |
1915 | search_paths, | |
1916 | maybe_sysroot: sysroot_opt, | |
1917 | target_triple, | |
1918 | test, | |
1919 | incremental, | |
1920 | debugging_opts, | |
1921 | prints, | |
1922 | borrowck_mode, | |
1923 | cg, | |
1924 | error_format, | |
1925 | externs, | |
1926 | unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), | |
1927 | crate_name, | |
1928 | alt_std_name: None, | |
1929 | libs, | |
1930 | debug_assertions, | |
1931 | actually_rustdoc: false, | |
1932 | trimmed_def_paths: TrimmedDefPaths::default(), | |
1933 | cli_forced_codegen_units: codegen_units, | |
1934 | cli_forced_thinlto_off: disable_thinlto, | |
1935 | remap_path_prefix, | |
1936 | edition, | |
1937 | json_artifact_notifications, | |
1938 | pretty, | |
1939 | } | |
1940 | } | |
1941 | ||
1942 | fn parse_pretty( | |
1943 | matches: &getopts::Matches, | |
1944 | debugging_opts: &DebuggingOptions, | |
1945 | efmt: ErrorOutputType, | |
1946 | ) -> Option<PpMode> { | |
1947 | let pretty = if debugging_opts.unstable_options { | |
1948 | matches.opt_default("pretty", "normal").map(|a| { | |
1949 | // stable pretty-print variants only | |
1950 | parse_pretty_inner(efmt, &a, false) | |
1951 | }) | |
1952 | } else { | |
1953 | None | |
1954 | }; | |
1955 | ||
1956 | return if pretty.is_none() { | |
1957 | debugging_opts.unpretty.as_ref().map(|a| { | |
1958 | // extended with unstable pretty-print variants | |
1959 | parse_pretty_inner(efmt, &a, true) | |
1960 | }) | |
1961 | } else { | |
1962 | pretty | |
1963 | }; | |
1964 | ||
1965 | fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode { | |
1966 | use PpMode::*; | |
1967 | use PpSourceMode::*; | |
1968 | let first = match (name, extended) { | |
1969 | ("normal", _) => PpmSource(PpmNormal), | |
1970 | ("identified", _) => PpmSource(PpmIdentified), | |
1971 | ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops), | |
1972 | ("expanded", _) => PpmSource(PpmExpanded), | |
1973 | ("expanded,identified", _) => PpmSource(PpmExpandedIdentified), | |
1974 | ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene), | |
1975 | ("hir", true) => PpmHir(PpmNormal), | |
1976 | ("hir,identified", true) => PpmHir(PpmIdentified), | |
1977 | ("hir,typed", true) => PpmHir(PpmTyped), | |
1978 | ("hir-tree", true) => PpmHirTree(PpmNormal), | |
1979 | ("mir", true) => PpmMir, | |
1980 | ("mir-cfg", true) => PpmMirCFG, | |
1981 | _ => { | |
1982 | if extended { | |
1983 | early_error( | |
1984 | efmt, | |
1985 | &format!( | |
1986 | "argument to `unpretty` must be one of `normal`, \ | |
1987 | `expanded`, `identified`, `expanded,identified`, \ | |
1988 | `expanded,hygiene`, `everybody_loops`, \ | |
1989 | `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \ | |
1990 | `mir` or `mir-cfg`; got {}", | |
1991 | name | |
1992 | ), | |
1993 | ); | |
1994 | } else { | |
1995 | early_error( | |
1996 | efmt, | |
1997 | &format!( | |
1998 | "argument to `pretty` must be one of `normal`, \ | |
1999 | `expanded`, `identified`, or `expanded,identified`; got {}", | |
2000 | name | |
2001 | ), | |
2002 | ); | |
2003 | } | |
2004 | } | |
2005 | }; | |
2006 | tracing::debug!("got unpretty option: {:?}", first); | |
2007 | first | |
2008 | } | |
2009 | } | |
2010 | ||
2011 | pub fn make_crate_type_option() -> RustcOptGroup { | |
2012 | opt::multi_s( | |
2013 | "", | |
2014 | "crate-type", | |
2015 | "Comma separated list of types of crates | |
2016 | for the compiler to emit", | |
2017 | "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]", | |
2018 | ) | |
2019 | } | |
2020 | ||
2021 | pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> { | |
2022 | let mut crate_types: Vec<CrateType> = Vec::new(); | |
2023 | for unparsed_crate_type in &list_list { | |
2024 | for part in unparsed_crate_type.split(',') { | |
2025 | let new_part = match part { | |
2026 | "lib" => default_lib_output(), | |
2027 | "rlib" => CrateType::Rlib, | |
2028 | "staticlib" => CrateType::Staticlib, | |
2029 | "dylib" => CrateType::Dylib, | |
2030 | "cdylib" => CrateType::Cdylib, | |
2031 | "bin" => CrateType::Executable, | |
2032 | "proc-macro" => CrateType::ProcMacro, | |
2033 | _ => return Err(format!("unknown crate type: `{}`", part)), | |
2034 | }; | |
2035 | if !crate_types.contains(&new_part) { | |
2036 | crate_types.push(new_part) | |
2037 | } | |
2038 | } | |
2039 | } | |
2040 | ||
2041 | Ok(crate_types) | |
2042 | } | |
2043 | ||
2044 | pub mod nightly_options { | |
2045 | use super::{ErrorOutputType, OptionStability, RustcOptGroup}; | |
2046 | use crate::early_error; | |
2047 | use rustc_feature::UnstableFeatures; | |
2048 | ||
2049 | pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { | |
2050 | match_is_nightly_build(matches) | |
2051 | && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") | |
2052 | } | |
2053 | ||
2054 | pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool { | |
2055 | is_nightly_build(matches.opt_str("crate-name").as_deref()) | |
2056 | } | |
2057 | ||
2058 | pub fn is_nightly_build(krate: Option<&str>) -> bool { | |
2059 | UnstableFeatures::from_environment(krate).is_nightly_build() | |
2060 | } | |
2061 | ||
2062 | pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) { | |
2063 | let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options"); | |
2064 | let really_allows_unstable_options = match_is_nightly_build(matches); | |
2065 | ||
2066 | for opt in flags.iter() { | |
2067 | if opt.stability == OptionStability::Stable { | |
2068 | continue; | |
2069 | } | |
2070 | if !matches.opt_present(opt.name) { | |
2071 | continue; | |
2072 | } | |
2073 | if opt.name != "Z" && !has_z_unstable_option { | |
2074 | early_error( | |
2075 | ErrorOutputType::default(), | |
2076 | &format!( | |
2077 | "the `-Z unstable-options` flag must also be passed to enable \ | |
2078 | the flag `{}`", | |
2079 | opt.name | |
2080 | ), | |
2081 | ); | |
2082 | } | |
2083 | if really_allows_unstable_options { | |
2084 | continue; | |
2085 | } | |
2086 | match opt.stability { | |
2087 | OptionStability::Unstable => { | |
2088 | let msg = format!( | |
2089 | "the option `{}` is only accepted on the \ | |
2090 | nightly compiler", | |
2091 | opt.name | |
2092 | ); | |
2093 | early_error(ErrorOutputType::default(), &msg); | |
2094 | } | |
2095 | OptionStability::Stable => {} | |
2096 | } | |
2097 | } | |
2098 | } | |
2099 | } | |
2100 | ||
2101 | impl fmt::Display for CrateType { | |
2102 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
2103 | match *self { | |
2104 | CrateType::Executable => "bin".fmt(f), | |
2105 | CrateType::Dylib => "dylib".fmt(f), | |
2106 | CrateType::Rlib => "rlib".fmt(f), | |
2107 | CrateType::Staticlib => "staticlib".fmt(f), | |
2108 | CrateType::Cdylib => "cdylib".fmt(f), | |
2109 | CrateType::ProcMacro => "proc-macro".fmt(f), | |
2110 | } | |
2111 | } | |
2112 | } | |
2113 | ||
2114 | #[derive(Copy, Clone, PartialEq, Debug)] | |
2115 | pub enum PpSourceMode { | |
2116 | PpmNormal, | |
2117 | PpmEveryBodyLoops, | |
2118 | PpmExpanded, | |
2119 | PpmIdentified, | |
2120 | PpmExpandedIdentified, | |
2121 | PpmExpandedHygiene, | |
2122 | PpmTyped, | |
2123 | } | |
2124 | ||
2125 | #[derive(Copy, Clone, PartialEq, Debug)] | |
2126 | pub enum PpMode { | |
2127 | PpmSource(PpSourceMode), | |
2128 | PpmHir(PpSourceMode), | |
2129 | PpmHirTree(PpSourceMode), | |
2130 | PpmMir, | |
2131 | PpmMirCFG, | |
2132 | } | |
2133 | ||
2134 | impl PpMode { | |
2135 | pub fn needs_ast_map(&self) -> bool { | |
2136 | use PpMode::*; | |
2137 | use PpSourceMode::*; | |
2138 | match *self { | |
2139 | PpmSource(PpmNormal | PpmIdentified) => false, | |
2140 | ||
2141 | PpmSource( | |
2142 | PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene, | |
2143 | ) | |
2144 | | PpmHir(_) | |
2145 | | PpmHirTree(_) | |
2146 | | PpmMir | |
2147 | | PpmMirCFG => true, | |
2148 | PpmSource(PpmTyped) => panic!("invalid state"), | |
2149 | } | |
2150 | } | |
2151 | ||
2152 | pub fn needs_analysis(&self) -> bool { | |
2153 | use PpMode::*; | |
2154 | matches!(*self, PpmMir | PpmMirCFG) | |
2155 | } | |
2156 | } | |
2157 | ||
2158 | /// Command-line arguments passed to the compiler have to be incorporated with | |
2159 | /// the dependency tracking system for incremental compilation. This module | |
2160 | /// provides some utilities to make this more convenient. | |
2161 | /// | |
2162 | /// The values of all command-line arguments that are relevant for dependency | |
2163 | /// tracking are hashed into a single value that determines whether the | |
2164 | /// incremental compilation cache can be re-used or not. This hashing is done | |
2165 | /// via the `DepTrackingHash` trait defined below, since the standard `Hash` | |
2166 | /// implementation might not be suitable (e.g., arguments are stored in a `Vec`, | |
2167 | /// the hash of which is order dependent, but we might not want the order of | |
2168 | /// arguments to make a difference for the hash). | |
2169 | /// | |
2170 | /// However, since the value provided by `Hash::hash` often *is* suitable, | |
2171 | /// especially for primitive types, there is the | |
2172 | /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the | |
2173 | /// `Hash` implementation for `DepTrackingHash`. It's important though that | |
2174 | /// we have an opt-in scheme here, so one is hopefully forced to think about | |
2175 | /// how the hash should be calculated when adding a new command-line argument. | |
2176 | crate mod dep_tracking { | |
2177 | use super::{ | |
2178 | CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, | |
2179 | OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath, | |
2180 | SymbolManglingVersion, TrimmedDefPaths, | |
2181 | }; | |
2182 | use crate::lint; | |
2183 | use crate::options::WasiExecModel; | |
2184 | use crate::utils::NativeLibKind; | |
2185 | use rustc_feature::UnstableFeatures; | |
2186 | use rustc_span::edition::Edition; | |
2187 | use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel}; | |
2188 | use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel}; | |
2189 | use std::collections::hash_map::DefaultHasher; | |
2190 | use std::collections::BTreeMap; | |
2191 | use std::hash::Hash; | |
2192 | use std::path::PathBuf; | |
2193 | ||
2194 | pub trait DepTrackingHash { | |
2195 | fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType); | |
2196 | } | |
2197 | ||
2198 | macro_rules! impl_dep_tracking_hash_via_hash { | |
2199 | ($t:ty) => { | |
2200 | impl DepTrackingHash for $t { | |
2201 | fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) { | |
2202 | Hash::hash(self, hasher); | |
2203 | } | |
2204 | } | |
2205 | }; | |
2206 | } | |
2207 | ||
2208 | macro_rules! impl_dep_tracking_hash_for_sortable_vec_of { | |
2209 | ($t:ty) => { | |
2210 | impl DepTrackingHash for Vec<$t> { | |
2211 | fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { | |
2212 | let mut elems: Vec<&$t> = self.iter().collect(); | |
2213 | elems.sort(); | |
2214 | Hash::hash(&elems.len(), hasher); | |
2215 | for (index, elem) in elems.iter().enumerate() { | |
2216 | Hash::hash(&index, hasher); | |
2217 | DepTrackingHash::hash(*elem, hasher, error_format); | |
2218 | } | |
2219 | } | |
2220 | } | |
2221 | }; | |
2222 | } | |
2223 | ||
2224 | impl_dep_tracking_hash_via_hash!(bool); | |
2225 | impl_dep_tracking_hash_via_hash!(usize); | |
2226 | impl_dep_tracking_hash_via_hash!(u64); | |
2227 | impl_dep_tracking_hash_via_hash!(String); | |
2228 | impl_dep_tracking_hash_via_hash!(PathBuf); | |
2229 | impl_dep_tracking_hash_via_hash!(lint::Level); | |
2230 | impl_dep_tracking_hash_via_hash!(Option<bool>); | |
2231 | impl_dep_tracking_hash_via_hash!(Option<usize>); | |
2232 | impl_dep_tracking_hash_via_hash!(Option<String>); | |
2233 | impl_dep_tracking_hash_via_hash!(Option<(String, u64)>); | |
2234 | impl_dep_tracking_hash_via_hash!(Option<Vec<String>>); | |
2235 | impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>); | |
2236 | impl_dep_tracking_hash_via_hash!(Option<RelocModel>); | |
2237 | impl_dep_tracking_hash_via_hash!(Option<CodeModel>); | |
2238 | impl_dep_tracking_hash_via_hash!(Option<TlsModel>); | |
2239 | impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>); | |
2240 | impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>); | |
2241 | impl_dep_tracking_hash_via_hash!(Option<RelroLevel>); | |
2242 | impl_dep_tracking_hash_via_hash!(Option<lint::Level>); | |
2243 | impl_dep_tracking_hash_via_hash!(Option<PathBuf>); | |
2244 | impl_dep_tracking_hash_via_hash!(CrateType); | |
2245 | impl_dep_tracking_hash_via_hash!(MergeFunctions); | |
2246 | impl_dep_tracking_hash_via_hash!(PanicStrategy); | |
2247 | impl_dep_tracking_hash_via_hash!(RelroLevel); | |
2248 | impl_dep_tracking_hash_via_hash!(Passes); | |
2249 | impl_dep_tracking_hash_via_hash!(OptLevel); | |
2250 | impl_dep_tracking_hash_via_hash!(LtoCli); | |
2251 | impl_dep_tracking_hash_via_hash!(DebugInfo); | |
2252 | impl_dep_tracking_hash_via_hash!(UnstableFeatures); | |
2253 | impl_dep_tracking_hash_via_hash!(OutputTypes); | |
2254 | impl_dep_tracking_hash_via_hash!(NativeLibKind); | |
2255 | impl_dep_tracking_hash_via_hash!(SanitizerSet); | |
2256 | impl_dep_tracking_hash_via_hash!(CFGuard); | |
2257 | impl_dep_tracking_hash_via_hash!(TargetTriple); | |
2258 | impl_dep_tracking_hash_via_hash!(Edition); | |
2259 | impl_dep_tracking_hash_via_hash!(LinkerPluginLto); | |
2260 | impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>); | |
2261 | impl_dep_tracking_hash_via_hash!(SwitchWithOptPath); | |
2262 | impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>); | |
2263 | impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>); | |
2264 | impl_dep_tracking_hash_via_hash!(TrimmedDefPaths); | |
2265 | ||
2266 | impl_dep_tracking_hash_for_sortable_vec_of!(String); | |
2267 | impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); | |
2268 | impl_dep_tracking_hash_for_sortable_vec_of!(CrateType); | |
2269 | impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); | |
2270 | impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind)); | |
2271 | impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); | |
2272 | ||
2273 | impl<T1, T2> DepTrackingHash for (T1, T2) | |
2274 | where | |
2275 | T1: DepTrackingHash, | |
2276 | T2: DepTrackingHash, | |
2277 | { | |
2278 | fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { | |
2279 | Hash::hash(&0, hasher); | |
2280 | DepTrackingHash::hash(&self.0, hasher, error_format); | |
2281 | Hash::hash(&1, hasher); | |
2282 | DepTrackingHash::hash(&self.1, hasher, error_format); | |
2283 | } | |
2284 | } | |
2285 | ||
2286 | impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3) | |
2287 | where | |
2288 | T1: DepTrackingHash, | |
2289 | T2: DepTrackingHash, | |
2290 | T3: DepTrackingHash, | |
2291 | { | |
2292 | fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { | |
2293 | Hash::hash(&0, hasher); | |
2294 | DepTrackingHash::hash(&self.0, hasher, error_format); | |
2295 | Hash::hash(&1, hasher); | |
2296 | DepTrackingHash::hash(&self.1, hasher, error_format); | |
2297 | Hash::hash(&2, hasher); | |
2298 | DepTrackingHash::hash(&self.2, hasher, error_format); | |
2299 | } | |
2300 | } | |
2301 | ||
2302 | // This is a stable hash because BTreeMap is a sorted container | |
2303 | pub fn stable_hash( | |
2304 | sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, | |
2305 | hasher: &mut DefaultHasher, | |
2306 | error_format: ErrorOutputType, | |
2307 | ) { | |
2308 | for (key, sub_hash) in sub_hashes { | |
2309 | // Using Hash::hash() instead of DepTrackingHash::hash() is fine for | |
2310 | // the keys, as they are just plain strings | |
2311 | Hash::hash(&key.len(), hasher); | |
2312 | Hash::hash(key, hasher); | |
2313 | sub_hash.hash(hasher, error_format); | |
2314 | } | |
2315 | } | |
2316 | } |