]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | //! Contains infrastructure for configuring the compiler, including parsing |
e1599b0c | 2 | //! command-line options. |
83c7162d | 3 | |
dfeec247 XL |
4 | pub use crate::options::*; |
5 | ||
dfeec247 | 6 | use crate::search_paths::SearchPath; |
17df50a5 | 7 | use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; |
60c5eb7d | 8 | use crate::{early_error, early_warn, Session}; |
04454e1e | 9 | use crate::{lint, HashStableContext}; |
1a4d82fc | 10 | |
5e7ed085 | 11 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
e1599b0c | 12 | |
487cf647 FG |
13 | use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; |
14 | use rustc_target::abi::Align; | |
f2b60f7d FG |
15 | use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo}; |
16 | use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; | |
1a4d82fc | 17 | |
5099ac24 | 18 | use crate::parse::{CrateCheckConfig, CrateConfig}; |
dfeec247 | 19 | use rustc_feature::UnstableFeatures; |
cdc7bbd5 | 20 | use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; |
dfeec247 XL |
21 | use rustc_span::source_map::{FileName, FilePathMapping}; |
22 | use rustc_span::symbol::{sym, Symbol}; | |
94222f64 | 23 | use rustc_span::RealFileName; |
ba9703b0 | 24 | use rustc_span::SourceFileHashAlgorithm; |
1a4d82fc | 25 | |
60c5eb7d | 26 | use rustc_errors::emitter::HumanReadableErrorType; |
9ffffee4 | 27 | use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg}; |
3157f602 | 28 | |
e1599b0c XL |
29 | use std::collections::btree_map::{ |
30 | Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, | |
31 | }; | |
dfeec247 | 32 | use std::collections::{BTreeMap, BTreeSet}; |
e1599b0c | 33 | use std::fmt; |
136023e0 | 34 | use std::hash::Hash; |
9c376795 | 35 | use std::iter; |
0531ce1d | 36 | use std::path::{Path, PathBuf}; |
dfeec247 | 37 | use std::str::{self, FromStr}; |
9c376795 | 38 | use std::sync::LazyLock; |
1a4d82fc | 39 | |
f2b60f7d FG |
40 | pub mod sigpipe; |
41 | ||
3c0e092e | 42 | /// The different settings that the `-C strip` flag can have. |
f9f354fc XL |
43 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] |
44 | pub enum Strip { | |
45 | /// Do not strip at all. | |
46 | None, | |
47 | ||
48 | /// Strip debuginfo. | |
49 | Debuginfo, | |
50 | ||
51 | /// Strip all symbols. | |
52 | Symbols, | |
53 | } | |
54 | ||
3dfed10e | 55 | /// The different settings that the `-C control-flow-guard` flag can have. |
74b04a01 XL |
56 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] |
57 | pub enum CFGuard { | |
58 | /// Do not emit Control Flow Guard metadata or checks. | |
59 | Disabled, | |
60 | ||
61 | /// Emit Control Flow Guard metadata but no checks. | |
62 | NoChecks, | |
63 | ||
64 | /// Emit Control Flow Guard metadata and checks. | |
65 | Checks, | |
66 | } | |
67 | ||
5099ac24 FG |
68 | /// The different settings that the `-Z cf-protection` flag can have. |
69 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
70 | pub enum CFProtection { | |
71 | /// Do not enable control-flow protection | |
72 | None, | |
73 | ||
74 | /// Emit control-flow protection for branches (enables indirect branch tracking). | |
75 | Branch, | |
76 | ||
77 | /// Emit control-flow protection for returns. | |
78 | Return, | |
79 | ||
80 | /// Emit control-flow protection for both branches and returns. | |
81 | Full, | |
82 | } | |
83 | ||
04454e1e | 84 | #[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)] |
1a4d82fc | 85 | pub enum OptLevel { |
0531ce1d XL |
86 | No, // -O0 |
87 | Less, // -O1 | |
88 | Default, // -O2 | |
a7813a04 | 89 | Aggressive, // -O3 |
0531ce1d XL |
90 | Size, // -Os |
91 | SizeMin, // -Oz | |
1a4d82fc JJ |
92 | } |
93 | ||
b7449926 XL |
94 | /// This is what the `LtoCli` values get mapped to after resolving defaults and |
95 | /// and taking other command line options into account. | |
cdc7bbd5 XL |
96 | /// |
97 | /// Note that linker plugin-based LTO is a different mechanism entirely. | |
e74abb32 | 98 | #[derive(Clone, PartialEq)] |
2c00a5a8 | 99 | pub enum Lto { |
cdc7bbd5 | 100 | /// Don't do any LTO whatsoever. |
2c00a5a8 XL |
101 | No, |
102 | ||
cdc7bbd5 | 103 | /// Do a full-crate-graph (inter-crate) LTO with ThinLTO. |
2c00a5a8 XL |
104 | Thin, |
105 | ||
cdc7bbd5 XL |
106 | /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is |
107 | /// only relevant if multiple CGUs are used. | |
2c00a5a8 XL |
108 | ThinLocal, |
109 | ||
cdc7bbd5 | 110 | /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO. |
2c00a5a8 XL |
111 | Fat, |
112 | } | |
113 | ||
b7449926 XL |
114 | /// The different settings that the `-C lto` flag can have. |
115 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
116 | pub enum LtoCli { | |
117 | /// `-C lto=no` | |
118 | No, | |
119 | /// `-C lto=yes` | |
120 | Yes, | |
121 | /// `-C lto` | |
122 | NoParam, | |
123 | /// `-C lto=thin` | |
124 | Thin, | |
125 | /// `-C lto=fat` | |
126 | Fat, | |
127 | /// No `-C lto` flag passed | |
128 | Unspecified, | |
129 | } | |
130 | ||
1b1a35ee XL |
131 | /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a |
132 | /// document highlighting each span of every statement (including terminators). `Terminator` and | |
133 | /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a | |
134 | /// computed span for the block, representing the entire range, covering the block's terminator and | |
135 | /// all of its statements. | |
136 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
137 | pub enum MirSpanview { | |
138 | /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement` | |
139 | Statement, | |
140 | /// `-Z dump_mir_spanview=terminator` | |
141 | Terminator, | |
142 | /// `-Z dump_mir_spanview=block` | |
143 | Block, | |
144 | } | |
145 | ||
5099ac24 | 146 | /// The different settings that the `-C instrument-coverage` flag can have. |
cdc7bbd5 | 147 | /// |
5099ac24 | 148 | /// Coverage instrumentation now supports combining `-C instrument-coverage` |
cdc7bbd5 XL |
149 | /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1` |
150 | /// and higher). Nevertheless, there are many variables, depending on options | |
151 | /// selected, code structure, and enabled attributes. If errors are encountered, | |
152 | /// either while compiling or when generating `llvm-cov show` reports, consider | |
153 | /// lowering the optimization level, including or excluding `-C link-dead-code`, | |
5099ac24 FG |
154 | /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions` |
155 | /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`. | |
cdc7bbd5 XL |
156 | /// |
157 | /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the | |
158 | /// coverage map, it will not attempt to generate synthetic functions for unused | |
159 | /// (and not code-generated) functions (whether they are generic or not). As a | |
160 | /// result, non-codegenned functions will not be included in the coverage map, | |
161 | /// and will not appear, as covered or uncovered, in coverage reports. | |
162 | /// | |
163 | /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map, | |
164 | /// unless the function has type parameters. | |
165 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
166 | pub enum InstrumentCoverage { | |
5099ac24 | 167 | /// Default `-C instrument-coverage` or `-C instrument-coverage=statement` |
cdc7bbd5 | 168 | All, |
5099ac24 | 169 | /// `-Zunstable-options -C instrument-coverage=except-unused-generics` |
cdc7bbd5 | 170 | ExceptUnusedGenerics, |
5099ac24 | 171 | /// `-Zunstable-options -C instrument-coverage=except-unused-functions` |
cdc7bbd5 | 172 | ExceptUnusedFunctions, |
5099ac24 | 173 | /// `-C instrument-coverage=off` (or `no`, etc.) |
cdc7bbd5 XL |
174 | Off, |
175 | } | |
176 | ||
9ffffee4 FG |
177 | /// Settings for `-Z instrument-xray` flag. |
178 | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] | |
179 | pub struct InstrumentXRay { | |
180 | /// `-Z instrument-xray=always`, force instrumentation | |
181 | pub always: bool, | |
182 | /// `-Z instrument-xray=never`, disable instrumentation | |
183 | pub never: bool, | |
184 | /// `-Z instrument-xray=ignore-loops`, ignore presence of loops, | |
185 | /// instrument functions based only on instruction count | |
186 | pub ignore_loops: bool, | |
187 | /// `-Z instrument-xray=instruction-threshold=N`, explicitly set instruction threshold | |
188 | /// for instrumentation, or `None` to use compiler's default | |
189 | pub instruction_threshold: Option<usize>, | |
190 | /// `-Z instrument-xray=skip-entry`, do not instrument function entry | |
191 | pub skip_entry: bool, | |
192 | /// `-Z instrument-xray=skip-exit`, do not instrument function exit | |
193 | pub skip_exit: bool, | |
194 | } | |
195 | ||
cdc7bbd5 | 196 | #[derive(Clone, PartialEq, Hash, Debug)] |
9fa01778 | 197 | pub enum LinkerPluginLto { |
94b46f34 | 198 | LinkerPlugin(PathBuf), |
8faf50e0 | 199 | LinkerPluginAuto, |
dfeec247 | 200 | Disabled, |
94b46f34 XL |
201 | } |
202 | ||
3c0e092e XL |
203 | /// Used with `-Z assert-incr-state`. |
204 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
205 | pub enum IncrementalStateAssertion { | |
206 | /// Found and loaded an existing session directory. | |
207 | /// | |
208 | /// Note that this says nothing about whether any particular query | |
209 | /// will be found to be red or green. | |
210 | Loaded, | |
211 | /// Did not load an existing session directory. | |
212 | NotLoaded, | |
213 | } | |
214 | ||
9fa01778 | 215 | impl LinkerPluginLto { |
8faf50e0 | 216 | pub fn enabled(&self) -> bool { |
94b46f34 | 217 | match *self { |
dfeec247 | 218 | LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true, |
9fa01778 | 219 | LinkerPluginLto::Disabled => false, |
94b46f34 XL |
220 | } |
221 | } | |
222 | } | |
223 | ||
3c0e092e XL |
224 | /// The different settings that can be enabled via the `-Z location-detail` flag. |
225 | #[derive(Clone, PartialEq, Hash, Debug)] | |
226 | pub struct LocationDetail { | |
227 | pub file: bool, | |
228 | pub line: bool, | |
229 | pub column: bool, | |
230 | } | |
231 | ||
232 | impl LocationDetail { | |
233 | pub fn all() -> Self { | |
234 | Self { file: true, line: true, column: true } | |
235 | } | |
236 | } | |
237 | ||
cdc7bbd5 | 238 | #[derive(Clone, PartialEq, Hash, Debug)] |
dc9dc135 | 239 | pub enum SwitchWithOptPath { |
48663c56 XL |
240 | Enabled(Option<PathBuf>), |
241 | Disabled, | |
242 | } | |
243 | ||
dc9dc135 | 244 | impl SwitchWithOptPath { |
48663c56 XL |
245 | pub fn enabled(&self) -> bool { |
246 | match *self { | |
dc9dc135 XL |
247 | SwitchWithOptPath::Enabled(_) => true, |
248 | SwitchWithOptPath::Disabled => false, | |
48663c56 XL |
249 | } |
250 | } | |
251 | } | |
252 | ||
04454e1e | 253 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)] |
3dfed10e | 254 | #[derive(Encodable, Decodable)] |
dc9dc135 XL |
255 | pub enum SymbolManglingVersion { |
256 | Legacy, | |
257 | V0, | |
258 | } | |
259 | ||
fc512014 | 260 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] |
b7449926 XL |
261 | pub enum DebugInfo { |
262 | None, | |
263 | Limited, | |
264 | Full, | |
1a4d82fc JJ |
265 | } |
266 | ||
a2a8927a XL |
267 | /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split |
268 | /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform | |
269 | /// uses DWARF for debug-information. | |
270 | /// | |
271 | /// Some debug-information requires link-time relocation and some does not. LLVM can partition | |
272 | /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split | |
273 | /// DWARF provides a mechanism which allows the linker to skip the sections which don't require | |
274 | /// link-time relocation - either by putting those sections in DWARF object files, or by keeping | |
275 | /// them in the object file in such a way that the linker will skip them. | |
276 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] | |
277 | pub enum SplitDwarfKind { | |
278 | /// Sections which do not require relocation are written into object file but ignored by the | |
279 | /// linker. | |
280 | Single, | |
281 | /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file | |
282 | /// which is ignored by the linker. | |
283 | Split, | |
284 | } | |
285 | ||
286 | impl FromStr for SplitDwarfKind { | |
287 | type Err = (); | |
288 | ||
289 | fn from_str(s: &str) -> Result<Self, ()> { | |
290 | Ok(match s { | |
291 | "single" => SplitDwarfKind::Single, | |
292 | "split" => SplitDwarfKind::Split, | |
293 | _ => return Err(()), | |
294 | }) | |
295 | } | |
296 | } | |
297 | ||
04454e1e | 298 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)] |
3dfed10e | 299 | #[derive(Encodable, Decodable)] |
1a4d82fc | 300 | pub enum OutputType { |
b039eaaf SL |
301 | Bitcode, |
302 | Assembly, | |
303 | LlvmAssembly, | |
cc61c64b | 304 | Mir, |
32a655c1 | 305 | Metadata, |
b039eaaf SL |
306 | Object, |
307 | Exe, | |
308 | DepInfo, | |
1a4d82fc JJ |
309 | } |
310 | ||
487cf647 FG |
311 | // Safety: Trivial C-Style enums have a stable sort order across compilation sessions. |
312 | unsafe impl StableOrd for OutputType {} | |
313 | ||
04454e1e FG |
314 | impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType { |
315 | type KeyType = Self; | |
316 | ||
317 | fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType { | |
318 | *self | |
319 | } | |
320 | } | |
ea8adc8c | 321 | |
92a42be0 SL |
322 | impl OutputType { |
323 | fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool { | |
324 | match *self { | |
48663c56 | 325 | OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true, |
0531ce1d XL |
326 | OutputType::Bitcode |
327 | | OutputType::Assembly | |
328 | | OutputType::LlvmAssembly | |
329 | | OutputType::Mir | |
48663c56 | 330 | | OutputType::Object => false, |
92a42be0 SL |
331 | } |
332 | } | |
333 | ||
334 | fn shorthand(&self) -> &'static str { | |
335 | match *self { | |
336 | OutputType::Bitcode => "llvm-bc", | |
337 | OutputType::Assembly => "asm", | |
338 | OutputType::LlvmAssembly => "llvm-ir", | |
cc61c64b | 339 | OutputType::Mir => "mir", |
92a42be0 | 340 | OutputType::Object => "obj", |
32a655c1 | 341 | OutputType::Metadata => "metadata", |
92a42be0 SL |
342 | OutputType::Exe => "link", |
343 | OutputType::DepInfo => "dep-info", | |
344 | } | |
345 | } | |
5bcae85e | 346 | |
abe05a73 XL |
347 | fn from_shorthand(shorthand: &str) -> Option<Self> { |
348 | Some(match shorthand { | |
0531ce1d XL |
349 | "asm" => OutputType::Assembly, |
350 | "llvm-ir" => OutputType::LlvmAssembly, | |
351 | "mir" => OutputType::Mir, | |
352 | "llvm-bc" => OutputType::Bitcode, | |
353 | "obj" => OutputType::Object, | |
354 | "metadata" => OutputType::Metadata, | |
355 | "link" => OutputType::Exe, | |
356 | "dep-info" => OutputType::DepInfo, | |
abe05a73 XL |
357 | _ => return None, |
358 | }) | |
359 | } | |
360 | ||
361 | fn shorthands_display() -> String { | |
362 | format!( | |
363 | "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`", | |
364 | OutputType::Bitcode.shorthand(), | |
365 | OutputType::Assembly.shorthand(), | |
366 | OutputType::LlvmAssembly.shorthand(), | |
367 | OutputType::Mir.shorthand(), | |
368 | OutputType::Object.shorthand(), | |
369 | OutputType::Metadata.shorthand(), | |
370 | OutputType::Exe.shorthand(), | |
371 | OutputType::DepInfo.shorthand(), | |
372 | ) | |
373 | } | |
374 | ||
5bcae85e SL |
375 | pub fn extension(&self) -> &'static str { |
376 | match *self { | |
377 | OutputType::Bitcode => "bc", | |
378 | OutputType::Assembly => "s", | |
379 | OutputType::LlvmAssembly => "ll", | |
cc61c64b | 380 | OutputType::Mir => "mir", |
5bcae85e | 381 | OutputType::Object => "o", |
32a655c1 | 382 | OutputType::Metadata => "rmeta", |
5bcae85e SL |
383 | OutputType::DepInfo => "d", |
384 | OutputType::Exe => "", | |
385 | } | |
386 | } | |
92a42be0 SL |
387 | } |
388 | ||
dc9dc135 | 389 | /// The type of diagnostics output to generate. |
476ff2be SL |
390 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
391 | pub enum ErrorOutputType { | |
dc9dc135 | 392 | /// Output meant for the consumption of humans. |
48663c56 | 393 | HumanReadable(HumanReadableErrorType), |
dc9dc135 | 394 | /// Output that's consumed by other tools such as `rustfix` or the `RLS`. |
48663c56 | 395 | Json { |
dc9dc135 | 396 | /// Render the JSON in a human readable way (with indents and newlines). |
48663c56 | 397 | pretty: bool, |
dc9dc135 XL |
398 | /// The JSON output includes a `rendered` field that includes the rendered |
399 | /// human output. | |
48663c56 XL |
400 | json_rendered: HumanReadableErrorType, |
401 | }, | |
476ff2be SL |
402 | } |
403 | ||
404 | impl Default for ErrorOutputType { | |
e1599b0c XL |
405 | fn default() -> Self { |
406 | Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)) | |
476ff2be SL |
407 | } |
408 | } | |
409 | ||
1b1a35ee | 410 | /// Parameter to control path trimming. |
3c0e092e | 411 | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] |
1b1a35ee XL |
412 | pub enum TrimmedDefPaths { |
413 | /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query | |
3c0e092e | 414 | #[default] |
1b1a35ee XL |
415 | Never, |
416 | /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug` | |
417 | Always, | |
418 | /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug` | |
419 | GoodPath, | |
420 | } | |
421 | ||
9ffffee4 FG |
422 | #[derive(Clone, Hash)] |
423 | pub enum ResolveDocLinks { | |
424 | /// Do not resolve doc links. | |
425 | None, | |
426 | /// Resolve doc links on exported items only for crate types that have metadata. | |
427 | ExportedMetadata, | |
428 | /// Resolve doc links on exported items. | |
429 | Exported, | |
430 | /// Resolve doc links on all items. | |
431 | All, | |
432 | } | |
433 | ||
e1599b0c XL |
434 | /// Use tree-based collections to cheaply get a deterministic `Hash` implementation. |
435 | /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break | |
136023e0 XL |
436 | /// dependency tracking for command-line arguments. Also only hash keys, since tracking |
437 | /// should only depend on the output types, not the paths they're written to. | |
04454e1e | 438 | #[derive(Clone, Debug, Hash, HashStable_Generic)] |
5bcae85e SL |
439 | pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>); |
440 | ||
441 | impl OutputTypes { | |
442 | pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes { | |
dfeec247 | 443 | OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone())))) |
5bcae85e SL |
444 | } |
445 | ||
446 | pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> { | |
447 | self.0.get(key) | |
448 | } | |
449 | ||
450 | pub fn contains_key(&self, key: &OutputType) -> bool { | |
451 | self.0.contains_key(key) | |
452 | } | |
453 | ||
416331ca | 454 | pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> { |
5bcae85e SL |
455 | self.0.keys() |
456 | } | |
457 | ||
416331ca | 458 | pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> { |
5bcae85e SL |
459 | self.0.values() |
460 | } | |
32a655c1 | 461 | |
83c7162d XL |
462 | pub fn len(&self) -> usize { |
463 | self.0.len() | |
464 | } | |
465 | ||
a2a8927a | 466 | /// Returns `true` if any of the output types require codegen or linking. |
94b46f34 | 467 | pub fn should_codegen(&self) -> bool { |
32a655c1 | 468 | self.0.keys().any(|k| match *k { |
0531ce1d XL |
469 | OutputType::Bitcode |
470 | | OutputType::Assembly | |
471 | | OutputType::LlvmAssembly | |
472 | | OutputType::Mir | |
473 | | OutputType::Object | |
474 | | OutputType::Exe => true, | |
475 | OutputType::Metadata | OutputType::DepInfo => false, | |
32a655c1 SL |
476 | }) |
477 | } | |
5869c6ff | 478 | |
a2a8927a | 479 | /// Returns `true` if any of the output types require linking. |
5869c6ff XL |
480 | pub fn should_link(&self) -> bool { |
481 | self.0.keys().any(|k| match *k { | |
482 | OutputType::Bitcode | |
483 | | OutputType::Assembly | |
484 | | OutputType::LlvmAssembly | |
485 | | OutputType::Mir | |
486 | | OutputType::Metadata | |
487 | | OutputType::Object | |
488 | | OutputType::DepInfo => false, | |
489 | OutputType::Exe => true, | |
490 | }) | |
491 | } | |
5bcae85e SL |
492 | } |
493 | ||
e1599b0c XL |
494 | /// Use tree-based collections to cheaply get a deterministic `Hash` implementation. |
495 | /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That | |
496 | /// would break dependency tracking for command-line arguments. | |
e74abb32 | 497 | #[derive(Clone)] |
48663c56 XL |
498 | pub struct Externs(BTreeMap<String, ExternEntry>); |
499 | ||
60c5eb7d | 500 | #[derive(Clone, Debug)] |
48663c56 | 501 | pub struct ExternEntry { |
60c5eb7d XL |
502 | pub location: ExternLocation, |
503 | /// Indicates this is a "private" dependency for the | |
504 | /// `exported_private_dependencies` lint. | |
505 | /// | |
506 | /// This can be set with the `priv` option like | |
507 | /// `--extern priv:name=foo.rlib`. | |
508 | pub is_private_dep: bool, | |
509 | /// Add the extern entry to the extern prelude. | |
510 | /// | |
511 | /// This can be disabled with the `noprelude` option like | |
512 | /// `--extern noprelude:name`. | |
513 | pub add_prelude: bool, | |
04454e1e FG |
514 | /// The extern entry shouldn't be considered for unused dependency warnings. |
515 | /// | |
516 | /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to | |
517 | /// suppress `unused-crate-dependencies` warnings. | |
518 | pub nounused_dep: bool, | |
60c5eb7d XL |
519 | } |
520 | ||
521 | #[derive(Clone, Debug)] | |
522 | pub enum ExternLocation { | |
523 | /// Indicates to look for the library in the search paths. | |
524 | /// | |
525 | /// Added via `--extern name`. | |
526 | FoundInLibrarySearchDirectories, | |
527 | /// The locations where this extern entry must be found. | |
528 | /// | |
529 | /// The `CrateLoader` is responsible for loading these and figuring out | |
530 | /// which one to use. | |
531 | /// | |
532 | /// Added via `--extern prelude_name=some_file.rlib` | |
5869c6ff | 533 | ExactPaths(BTreeSet<CanonicalizedPath>), |
48663c56 | 534 | } |
5bcae85e SL |
535 | |
536 | impl Externs { | |
cdc7bbd5 | 537 | /// Used for testing. |
48663c56 | 538 | pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs { |
5bcae85e SL |
539 | Externs(data) |
540 | } | |
541 | ||
48663c56 | 542 | pub fn get(&self, key: &str) -> Option<&ExternEntry> { |
5bcae85e SL |
543 | self.0.get(key) |
544 | } | |
545 | ||
416331ca | 546 | pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> { |
5bcae85e SL |
547 | self.0.iter() |
548 | } | |
cdc7bbd5 XL |
549 | |
550 | pub fn len(&self) -> usize { | |
551 | self.0.len() | |
552 | } | |
1a4d82fc JJ |
553 | } |
554 | ||
60c5eb7d XL |
555 | impl ExternEntry { |
556 | fn new(location: ExternLocation) -> ExternEntry { | |
04454e1e | 557 | ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false } |
60c5eb7d XL |
558 | } |
559 | ||
5869c6ff | 560 | pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> { |
60c5eb7d XL |
561 | match &self.location { |
562 | ExternLocation::ExactPaths(set) => Some(set.iter()), | |
563 | _ => None, | |
564 | } | |
565 | } | |
566 | } | |
48663c56 | 567 | |
7cac9316 | 568 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
1a4d82fc JJ |
569 | pub enum PrintRequest { |
570 | FileNames, | |
571 | Sysroot, | |
74b04a01 | 572 | TargetLibdir, |
1a4d82fc | 573 | CrateName, |
7453a54e | 574 | Cfg, |
2b03887a | 575 | CallingConventions, |
7453a54e | 576 | TargetList, |
5bcae85e SL |
577 | TargetCPUs, |
578 | TargetFeatures, | |
579 | RelocationModels, | |
580 | CodeModels, | |
abe05a73 | 581 | TlsModels, |
476ff2be | 582 | TargetSpec, |
ea8adc8c | 583 | NativeStaticLibs, |
3c0e092e | 584 | StackProtectorStrategies, |
5099ac24 | 585 | LinkArgs, |
487cf647 | 586 | SplitDebuginfo, |
1a4d82fc JJ |
587 | } |
588 | ||
9c376795 FG |
589 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
590 | pub enum TraitSolver { | |
591 | /// Classic trait solver in `rustc_trait_selection::traits::select` | |
592 | Classic, | |
593 | /// Chalk trait solver | |
594 | Chalk, | |
595 | /// Experimental trait solver in `rustc_trait_selection::solve` | |
596 | Next, | |
597 | } | |
598 | ||
1a4d82fc | 599 | pub enum Input { |
e1599b0c | 600 | /// Load source code from a file. |
c34b1796 | 601 | File(PathBuf), |
e1599b0c | 602 | /// Load source code from a string. |
54a0048b | 603 | Str { |
e1599b0c | 604 | /// A string that is shown in place of a filename. |
ff7c6d11 | 605 | name: FileName, |
e1599b0c | 606 | /// An anonymous string containing the source code. |
54a0048b SL |
607 | input: String, |
608 | }, | |
1a4d82fc JJ |
609 | } |
610 | ||
611 | impl Input { | |
0bf4aa26 | 612 | pub fn filestem(&self) -> &str { |
1a4d82fc | 613 | match *self { |
0bf4aa26 XL |
614 | Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(), |
615 | Input::Str { .. } => "rust_out", | |
1a4d82fc JJ |
616 | } |
617 | } | |
94b46f34 | 618 | |
532ac7d7 XL |
619 | pub fn source_name(&self) -> FileName { |
620 | match *self { | |
621 | Input::File(ref ifile) => ifile.clone().into(), | |
622 | Input::Str { ref name, .. } => name.clone(), | |
623 | } | |
624 | } | |
9c376795 FG |
625 | |
626 | pub fn opt_path(&self) -> Option<&Path> { | |
627 | match self { | |
628 | Input::File(file) => Some(file), | |
629 | Input::Str { name, .. } => match name { | |
630 | FileName::Real(real) => real.local_path(), | |
631 | FileName::QuoteExpansion(_) => None, | |
632 | FileName::Anon(_) => None, | |
633 | FileName::MacroExpansion(_) => None, | |
634 | FileName::ProcMacroSourceCode(_) => None, | |
635 | FileName::CfgSpec(_) => None, | |
636 | FileName::CliCrateAttr(_) => None, | |
637 | FileName::Custom(_) => None, | |
638 | FileName::DocTest(path, _) => Some(path), | |
639 | FileName::InlineAsm(_) => None, | |
640 | }, | |
641 | } | |
642 | } | |
1a4d82fc JJ |
643 | } |
644 | ||
04454e1e | 645 | #[derive(Clone, Hash, Debug, HashStable_Generic)] |
1a4d82fc | 646 | pub struct OutputFilenames { |
c34b1796 | 647 | pub out_directory: PathBuf, |
dfeec247 | 648 | filestem: String, |
c34b1796 | 649 | pub single_output_file: Option<PathBuf>, |
3c0e092e | 650 | pub temps_directory: Option<PathBuf>, |
5bcae85e | 651 | pub outputs: OutputTypes, |
1a4d82fc JJ |
652 | } |
653 | ||
74b04a01 | 654 | pub const RLINK_EXT: &str = "rlink"; |
abe05a73 | 655 | pub const RUST_CGU_EXT: &str = "rcgu"; |
fc512014 | 656 | pub const DWARF_OBJECT_EXT: &str = "dwo"; |
5bcae85e | 657 | |
1a4d82fc | 658 | impl OutputFilenames { |
dfeec247 XL |
659 | pub fn new( |
660 | out_directory: PathBuf, | |
661 | out_filestem: String, | |
662 | single_output_file: Option<PathBuf>, | |
3c0e092e | 663 | temps_directory: Option<PathBuf>, |
dfeec247 XL |
664 | extra: String, |
665 | outputs: OutputTypes, | |
666 | ) -> Self { | |
667 | OutputFilenames { | |
668 | out_directory, | |
669 | single_output_file, | |
3c0e092e | 670 | temps_directory, |
dfeec247 | 671 | outputs, |
5e7ed085 | 672 | filestem: format!("{out_filestem}{extra}"), |
dfeec247 XL |
673 | } |
674 | } | |
675 | ||
c34b1796 | 676 | pub fn path(&self, flavor: OutputType) -> PathBuf { |
0531ce1d XL |
677 | self.outputs |
678 | .get(&flavor) | |
679 | .and_then(|p| p.to_owned()) | |
b039eaaf | 680 | .or_else(|| self.single_output_file.clone()) |
3c0e092e XL |
681 | .unwrap_or_else(|| self.output_path(flavor)) |
682 | } | |
683 | ||
684 | /// Gets the output path where a compilation artifact of the given type | |
685 | /// should be placed on disk. | |
686 | pub fn output_path(&self, flavor: OutputType) -> PathBuf { | |
687 | let extension = flavor.extension(); | |
487cf647 | 688 | self.with_directory_and_extension(&self.out_directory, extension) |
5bcae85e SL |
689 | } |
690 | ||
9fa01778 | 691 | /// Gets the path where a compilation artifact of the given type for the |
5bcae85e SL |
692 | /// given codegen unit should be placed on disk. If codegen_unit_name is |
693 | /// None, a path distinct from those of any codegen unit will be generated. | |
0531ce1d | 694 | pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf { |
5bcae85e SL |
695 | let extension = flavor.extension(); |
696 | self.temp_path_ext(extension, codegen_unit_name) | |
1a4d82fc JJ |
697 | } |
698 | ||
fc512014 XL |
699 | /// Like `temp_path`, but specifically for dwarf objects. |
700 | pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf { | |
701 | self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name) | |
702 | } | |
703 | ||
704 | /// Like `temp_path`, but also supports things where there is no corresponding | |
9fa01778 | 705 | /// OutputType, like noopt-bitcode or lto-bitcode. |
0531ce1d | 706 | pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { |
5bcae85e SL |
707 | let mut extension = String::new(); |
708 | ||
709 | if let Some(codegen_unit_name) = codegen_unit_name { | |
ea8adc8c | 710 | extension.push_str(codegen_unit_name); |
1a4d82fc | 711 | } |
5bcae85e SL |
712 | |
713 | if !ext.is_empty() { | |
714 | if !extension.is_empty() { | |
1b1a35ee | 715 | extension.push('.'); |
ea8adc8c | 716 | extension.push_str(RUST_CGU_EXT); |
1b1a35ee | 717 | extension.push('.'); |
5bcae85e SL |
718 | } |
719 | ||
720 | extension.push_str(ext); | |
721 | } | |
722 | ||
3c0e092e XL |
723 | let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory); |
724 | ||
487cf647 | 725 | self.with_directory_and_extension(temps_directory, &extension) |
1a4d82fc JJ |
726 | } |
727 | ||
c34b1796 | 728 | pub fn with_extension(&self, extension: &str) -> PathBuf { |
3c0e092e XL |
729 | self.with_directory_and_extension(&self.out_directory, extension) |
730 | } | |
731 | ||
732 | fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf { | |
733 | let mut path = directory.join(&self.filestem); | |
dfeec247 XL |
734 | path.set_extension(extension); |
735 | path | |
1a4d82fc | 736 | } |
fc512014 | 737 | |
fc512014 XL |
738 | /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF |
739 | /// mode is being used, which is the logic that this function is intended to encapsulate. | |
740 | pub fn split_dwarf_path( | |
741 | &self, | |
5869c6ff | 742 | split_debuginfo_kind: SplitDebuginfo, |
a2a8927a | 743 | split_dwarf_kind: SplitDwarfKind, |
fc512014 XL |
744 | cgu_name: Option<&str>, |
745 | ) -> Option<PathBuf> { | |
746 | let obj_out = self.temp_path(OutputType::Object, cgu_name); | |
747 | let dwo_out = self.temp_path_dwo(cgu_name); | |
a2a8927a XL |
748 | match (split_debuginfo_kind, split_dwarf_kind) { |
749 | (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None, | |
fc512014 XL |
750 | // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes |
751 | // (pointing at the path which is being determined here). Use the path to the current | |
752 | // object file. | |
a2a8927a XL |
753 | (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => { |
754 | Some(obj_out) | |
755 | } | |
fc512014 | 756 | // Split mode emits the DWARF into a different file, use that path. |
a2a8927a XL |
757 | (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => { |
758 | Some(dwo_out) | |
759 | } | |
fc512014 XL |
760 | } |
761 | } | |
1a4d82fc JJ |
762 | } |
763 | ||
764 | pub fn host_triple() -> &'static str { | |
765 | // Get the host triple out of the build environment. This ensures that our | |
766 | // idea of the host triple is the same as for the set of libraries we've | |
9c376795 | 767 | // actually built. We can't just take LLVM's host triple because they |
1a4d82fc JJ |
768 | // normalize all ix86 architectures to i386. |
769 | // | |
770 | // Instead of grabbing the host triple (for the current host), we grab (at | |
771 | // compile time) the target triple that this rustc is built with and | |
772 | // calling that (at runtime) the host triple. | |
0531ce1d | 773 | (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE") |
1a4d82fc JJ |
774 | } |
775 | ||
b7449926 XL |
776 | impl Default for Options { |
777 | fn default() -> Options { | |
778 | Options { | |
3c0e092e | 779 | assert_incr_state: None, |
b7449926 XL |
780 | crate_types: Vec::new(), |
781 | optimize: OptLevel::No, | |
782 | debuginfo: DebugInfo::None, | |
783 | lint_opts: Vec::new(), | |
784 | lint_cap: None, | |
785 | describe_lints: false, | |
786 | output_types: OutputTypes(BTreeMap::new()), | |
0731742a | 787 | search_paths: vec![], |
b7449926 XL |
788 | maybe_sysroot: None, |
789 | target_triple: TargetTriple::from_triple(host_triple()), | |
790 | test: false, | |
791 | incremental: None, | |
064997fb | 792 | unstable_opts: Default::default(), |
b7449926 | 793 | prints: Vec::new(), |
17df50a5 | 794 | cg: Default::default(), |
b7449926 | 795 | error_format: ErrorOutputType::default(), |
064997fb | 796 | diagnostic_width: None, |
b7449926 XL |
797 | externs: Externs(BTreeMap::new()), |
798 | crate_name: None, | |
b7449926 XL |
799 | libs: Vec::new(), |
800 | unstable_features: UnstableFeatures::Disallow, | |
801 | debug_assertions: true, | |
802 | actually_rustdoc: false, | |
9ffffee4 | 803 | resolve_doc_links: ResolveDocLinks::None, |
1b1a35ee | 804 | trimmed_def_paths: TrimmedDefPaths::default(), |
b7449926 | 805 | cli_forced_codegen_units: None, |
487cf647 | 806 | cli_forced_local_thinlto_off: false, |
b7449926 | 807 | remap_path_prefix: Vec::new(), |
cdc7bbd5 | 808 | real_rust_source_base_dir: None, |
b7449926 | 809 | edition: DEFAULT_EDITION, |
416331ca | 810 | json_artifact_notifications: false, |
04454e1e | 811 | json_unused_externs: JsonUnusedExterns::No, |
a2a8927a | 812 | json_future_incompat: false, |
60c5eb7d | 813 | pretty: None, |
94222f64 | 814 | working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()), |
b7449926 | 815 | } |
1a4d82fc JJ |
816 | } |
817 | } | |
818 | ||
54a0048b | 819 | impl Options { |
9fa01778 | 820 | /// Returns `true` if there is a reason to build the dep graph. |
54a0048b | 821 | pub fn build_dep_graph(&self) -> bool { |
dfeec247 | 822 | self.incremental.is_some() |
064997fb FG |
823 | || self.unstable_opts.dump_dep_graph |
824 | || self.unstable_opts.query_dep_graph | |
54a0048b | 825 | } |
5bcae85e | 826 | |
7cac9316 | 827 | pub fn file_path_mapping(&self) -> FilePathMapping { |
0531ce1d | 828 | FilePathMapping::new(self.remap_path_prefix.clone()) |
7cac9316 | 829 | } |
ff7c6d11 | 830 | |
e1599b0c | 831 | /// Returns `true` if there will be an output file generated. |
ff7c6d11 | 832 | pub fn will_create_output_file(&self) -> bool { |
064997fb FG |
833 | !self.unstable_opts.parse_only && // The file is just being parsed |
834 | !self.unstable_opts.ls // The file is just being queried | |
ff7c6d11 | 835 | } |
b7449926 XL |
836 | |
837 | #[inline] | |
838 | pub fn share_generics(&self) -> bool { | |
064997fb | 839 | match self.unstable_opts.share_generics { |
b7449926 | 840 | Some(setting) => setting, |
dfeec247 XL |
841 | None => match self.optimize { |
842 | OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true, | |
843 | OptLevel::Default | OptLevel::Aggressive => false, | |
844 | }, | |
845 | } | |
846 | } | |
a2a8927a XL |
847 | |
848 | pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { | |
849 | self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) | |
850 | } | |
9c376795 FG |
851 | |
852 | #[allow(rustc::bad_opt_access)] | |
853 | pub fn incremental_relative_spans(&self) -> bool { | |
854 | self.unstable_opts.incremental_relative_spans | |
855 | || (self.unstable_features.is_nightly_build() && self.incremental.is_some()) | |
856 | } | |
dfeec247 XL |
857 | } |
858 | ||
064997fb | 859 | impl UnstableOptions { |
dfeec247 XL |
860 | pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags { |
861 | HandlerFlags { | |
862 | can_emit_warnings, | |
863 | treat_err_as_bug: self.treat_err_as_bug, | |
864 | dont_buffer_diagnostics: self.dont_buffer_diagnostics, | |
865 | report_delayed_bugs: self.report_delayed_bugs, | |
74b04a01 | 866 | macro_backtrace: self.macro_backtrace, |
ba9703b0 | 867 | deduplicate_diagnostics: self.deduplicate_diagnostics, |
487cf647 | 868 | track_diagnostics: self.track_diagnostics, |
b7449926 XL |
869 | } |
870 | } | |
54a0048b SL |
871 | } |
872 | ||
9fa01778 | 873 | // The type of entry function, so users can have their own entry functions |
04454e1e | 874 | #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)] |
1a4d82fc | 875 | pub enum EntryFnType { |
f2b60f7d FG |
876 | Main { |
877 | /// Specifies what to do with `SIGPIPE` before calling `fn main()`. | |
878 | /// | |
879 | /// What values that are valid and what they mean must be in sync | |
880 | /// across rustc and libstd, but we don't want it public in libstd, | |
881 | /// so we take a bit of an unusual approach with simple constants | |
882 | /// and an `include!()`. | |
883 | sigpipe: u8, | |
884 | }, | |
b7449926 | 885 | Start, |
1a4d82fc JJ |
886 | } |
887 | ||
3dfed10e | 888 | #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] |
04454e1e | 889 | #[derive(HashStable_Generic)] |
1a4d82fc | 890 | pub enum CrateType { |
b7449926 XL |
891 | Executable, |
892 | Dylib, | |
893 | Rlib, | |
894 | Staticlib, | |
895 | Cdylib, | |
896 | ProcMacro, | |
1a4d82fc JJ |
897 | } |
898 | ||
a2a8927a | 899 | impl CrateType { |
9ffffee4 FG |
900 | pub fn has_metadata(self) -> bool { |
901 | match self { | |
902 | CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true, | |
903 | CrateType::Executable | CrateType::Cdylib | CrateType::Staticlib => false, | |
a2a8927a XL |
904 | } |
905 | } | |
906 | } | |
907 | ||
cdc7bbd5 | 908 | #[derive(Clone, Hash, Debug, PartialEq, Eq)] |
1a4d82fc | 909 | pub enum Passes { |
b7449926 XL |
910 | Some(Vec<String>), |
911 | All, | |
1a4d82fc JJ |
912 | } |
913 | ||
914 | impl Passes { | |
915 | pub fn is_empty(&self) -> bool { | |
916 | match *self { | |
b7449926 XL |
917 | Passes::Some(ref v) => v.is_empty(), |
918 | Passes::All => false, | |
1a4d82fc JJ |
919 | } |
920 | } | |
a2a8927a XL |
921 | |
922 | pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) { | |
923 | match *self { | |
924 | Passes::Some(ref mut v) => v.extend(passes), | |
925 | Passes::All => {} | |
926 | } | |
927 | } | |
1a4d82fc JJ |
928 | } |
929 | ||
5099ac24 FG |
930 | #[derive(Clone, Copy, Hash, Debug, PartialEq)] |
931 | pub enum PAuthKey { | |
932 | A, | |
933 | B, | |
934 | } | |
935 | ||
936 | #[derive(Clone, Copy, Hash, Debug, PartialEq)] | |
937 | pub struct PacRet { | |
938 | pub leaf: bool, | |
939 | pub key: PAuthKey, | |
940 | } | |
941 | ||
9c376795 | 942 | #[derive(Clone, Copy, Hash, Debug, PartialEq, Default)] |
5099ac24 FG |
943 | pub struct BranchProtection { |
944 | pub bti: bool, | |
945 | pub pac_ret: Option<PacRet>, | |
946 | } | |
947 | ||
e74abb32 | 948 | pub const fn default_lib_output() -> CrateType { |
b7449926 | 949 | CrateType::Rlib |
1a4d82fc JJ |
950 | } |
951 | ||
cdc7bbd5 | 952 | fn default_configuration(sess: &Session) -> CrateConfig { |
5099ac24 | 953 | // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below. |
29967ef6 XL |
954 | let end = &sess.target.endian; |
955 | let arch = &sess.target.arch; | |
956 | let wordsz = sess.target.pointer_width.to_string(); | |
957 | let os = &sess.target.os; | |
958 | let env = &sess.target.env; | |
136023e0 | 959 | let abi = &sess.target.abi; |
29967ef6 XL |
960 | let vendor = &sess.target.vendor; |
961 | let min_atomic_width = sess.target.min_atomic_width(); | |
962 | let max_atomic_width = sess.target.max_atomic_width(); | |
963 | let atomic_cas = sess.target.atomic_cas; | |
487cf647 | 964 | let layout = sess.target.parse_data_layout().unwrap_or_else(|err| { |
f2b60f7d | 965 | sess.emit_fatal(err); |
1b1a35ee | 966 | }); |
1a4d82fc | 967 | |
f2b60f7d | 968 | let mut ret = CrateConfig::default(); |
136023e0 | 969 | ret.reserve(7); // the minimum number of insertions |
476ff2be | 970 | // Target bindings. |
3dfed10e | 971 | ret.insert((sym::target_os, Some(Symbol::intern(os)))); |
5e7ed085 | 972 | for fam in sess.target.families.as_ref() { |
3dfed10e XL |
973 | ret.insert((sym::target_family, Some(Symbol::intern(fam)))); |
974 | if fam == "windows" { | |
975 | ret.insert((sym::windows, None)); | |
976 | } else if fam == "unix" { | |
977 | ret.insert((sym::unix, None)); | |
32a655c1 SL |
978 | } |
979 | } | |
3dfed10e | 980 | ret.insert((sym::target_arch, Some(Symbol::intern(arch)))); |
5869c6ff | 981 | ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str())))); |
29967ef6 | 982 | ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz)))); |
3dfed10e | 983 | ret.insert((sym::target_env, Some(Symbol::intern(env)))); |
136023e0 | 984 | ret.insert((sym::target_abi, Some(Symbol::intern(abi)))); |
3dfed10e | 985 | ret.insert((sym::target_vendor, Some(Symbol::intern(vendor)))); |
a2a8927a | 986 | if sess.target.has_thread_local { |
dc9dc135 | 987 | ret.insert((sym::target_thread_local, None)); |
9cc50fc6 | 988 | } |
9ffffee4 | 989 | let mut has_atomic = false; |
136023e0 | 990 | for (i, align) in [ |
1b1a35ee XL |
991 | (8, layout.i8_align.abi), |
992 | (16, layout.i16_align.abi), | |
993 | (32, layout.i32_align.abi), | |
994 | (64, layout.i64_align.abi), | |
995 | (128, layout.i128_align.abi), | |
996 | ] { | |
32a655c1 | 997 | if i >= min_atomic_width && i <= max_atomic_width { |
9ffffee4 | 998 | has_atomic = true; |
1b1a35ee | 999 | let mut insert_atomic = |s, align: Align| { |
dfeec247 | 1000 | ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s)))); |
e74abb32 | 1001 | if atomic_cas { |
dfeec247 | 1002 | ret.insert((sym::target_has_atomic, Some(Symbol::intern(s)))); |
e74abb32 | 1003 | } |
1b1a35ee XL |
1004 | if align.bits() == i { |
1005 | ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s)))); | |
1006 | } | |
e74abb32 XL |
1007 | }; |
1008 | let s = i.to_string(); | |
1b1a35ee | 1009 | insert_atomic(&s, align); |
29967ef6 | 1010 | if s == wordsz { |
1b1a35ee | 1011 | insert_atomic("ptr", layout.pointer_align.abi); |
a7813a04 XL |
1012 | } |
1013 | } | |
1014 | } | |
9ffffee4 FG |
1015 | if sess.is_nightly_build() && has_atomic { |
1016 | ret.insert((sym::target_has_atomic_load_store, None)); | |
1017 | if atomic_cas { | |
1018 | ret.insert((sym::target_has_atomic, None)); | |
1019 | } | |
1020 | } | |
f035d41b | 1021 | |
29967ef6 XL |
1022 | let panic_strategy = sess.panic_strategy(); |
1023 | ret.insert((sym::panic, Some(panic_strategy.desc_symbol()))); | |
1024 | ||
9ffffee4 FG |
1025 | for mut s in sess.opts.unstable_opts.sanitizer { |
1026 | // KASAN should use the same attribute name as ASAN, as it's still ASAN | |
1027 | // under the hood | |
1028 | if s == SanitizerSet::KERNELADDRESS { | |
1029 | s = SanitizerSet::ADDRESS; | |
1030 | } | |
1031 | ||
60c5eb7d XL |
1032 | let symbol = Symbol::intern(&s.to_string()); |
1033 | ret.insert((sym::sanitize, Some(symbol))); | |
1034 | } | |
f035d41b | 1035 | |
c34b1796 | 1036 | if sess.opts.debug_assertions { |
3dfed10e | 1037 | ret.insert((sym::debug_assertions, None)); |
c34b1796 | 1038 | } |
064997fb | 1039 | // JUSTIFICATION: before wrapper fn is available |
f2b60f7d | 1040 | #[allow(rustc::bad_opt_access)] |
b7449926 | 1041 | if sess.opts.crate_types.contains(&CrateType::ProcMacro) { |
dc9dc135 | 1042 | ret.insert((sym::proc_macro, None)); |
9e0c209e | 1043 | } |
0bf4aa26 | 1044 | ret |
1a4d82fc JJ |
1045 | } |
1046 | ||
e1599b0c | 1047 | /// Converts the crate `cfg!` configuration from `String` to `Symbol`. |
532ac7d7 XL |
1048 | /// `rustc_interface::interface::Config` accepts this in the compiler configuration, |
1049 | /// but the symbol interner is not yet set up then, so we must convert it later. | |
60c5eb7d | 1050 | pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig { |
dfeec247 | 1051 | cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect() |
532ac7d7 XL |
1052 | } |
1053 | ||
5099ac24 FG |
1054 | /// The parsed `--check-cfg` options |
1055 | pub struct CheckCfg<T = String> { | |
5e7ed085 FG |
1056 | /// The set of all `names()`, if None no name checking is performed |
1057 | pub names_valid: Option<FxHashSet<T>>, | |
1058 | /// Is well known values activated | |
1059 | pub well_known_values: bool, | |
1060 | /// The set of all `values()` | |
1061 | pub values_valid: FxHashMap<T, FxHashSet<T>>, | |
5099ac24 FG |
1062 | } |
1063 | ||
1064 | impl<T> Default for CheckCfg<T> { | |
1065 | fn default() -> Self { | |
1066 | CheckCfg { | |
5e7ed085 FG |
1067 | names_valid: Default::default(), |
1068 | values_valid: Default::default(), | |
1069 | well_known_values: false, | |
5099ac24 FG |
1070 | } |
1071 | } | |
1072 | } | |
1073 | ||
1074 | impl<T> CheckCfg<T> { | |
1075 | fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> { | |
1076 | CheckCfg { | |
5e7ed085 FG |
1077 | names_valid: self |
1078 | .names_valid | |
1079 | .as_ref() | |
1080 | .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()), | |
1081 | values_valid: self | |
1082 | .values_valid | |
1083 | .iter() | |
1084 | .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect())) | |
1085 | .collect(), | |
1086 | well_known_values: self.well_known_values, | |
5099ac24 FG |
1087 | } |
1088 | } | |
1089 | } | |
1090 | ||
1091 | /// Converts the crate `--check-cfg` options from `String` to `Symbol`. | |
1092 | /// `rustc_interface::interface::Config` accepts this in the compiler configuration, | |
1093 | /// but the symbol interner is not yet set up then, so we must convert it later. | |
1094 | pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig { | |
1095 | cfg.map_data(|s| Symbol::intern(s)) | |
1096 | } | |
1097 | ||
1098 | impl CrateCheckConfig { | |
1099 | /// Fills a `CrateCheckConfig` with well-known configuration names. | |
5e7ed085 FG |
1100 | fn fill_well_known_names(&mut self) { |
1101 | // NOTE: This should be kept in sync with `default_configuration` and | |
1102 | // `fill_well_known_values` | |
5099ac24 | 1103 | const WELL_KNOWN_NAMES: &[Symbol] = &[ |
5e7ed085 | 1104 | // rustc |
5099ac24 FG |
1105 | sym::unix, |
1106 | sym::windows, | |
1107 | sym::target_os, | |
1108 | sym::target_family, | |
1109 | sym::target_arch, | |
1110 | sym::target_endian, | |
1111 | sym::target_pointer_width, | |
1112 | sym::target_env, | |
1113 | sym::target_abi, | |
1114 | sym::target_vendor, | |
1115 | sym::target_thread_local, | |
1116 | sym::target_has_atomic_load_store, | |
1117 | sym::target_has_atomic, | |
1118 | sym::target_has_atomic_equal_alignment, | |
04454e1e | 1119 | sym::target_feature, |
5099ac24 FG |
1120 | sym::panic, |
1121 | sym::sanitize, | |
1122 | sym::debug_assertions, | |
1123 | sym::proc_macro, | |
1124 | sym::test, | |
5e7ed085 FG |
1125 | sym::feature, |
1126 | // rustdoc | |
5099ac24 FG |
1127 | sym::doc, |
1128 | sym::doctest, | |
5e7ed085 FG |
1129 | // miri |
1130 | sym::miri, | |
5099ac24 | 1131 | ]; |
5e7ed085 FG |
1132 | |
1133 | // We only insert well-known names if `names()` was activated | |
1134 | if let Some(names_valid) = &mut self.names_valid { | |
1135 | names_valid.extend(WELL_KNOWN_NAMES); | |
5099ac24 FG |
1136 | } |
1137 | } | |
1138 | ||
5e7ed085 FG |
1139 | /// Fills a `CrateCheckConfig` with well-known configuration values. |
1140 | fn fill_well_known_values(&mut self) { | |
1141 | if !self.well_known_values { | |
1142 | return; | |
1143 | } | |
1144 | ||
1145 | // NOTE: This should be kept in sync with `default_configuration` and | |
1146 | // `fill_well_known_names` | |
1147 | ||
1148 | let panic_values = &PanicStrategy::all(); | |
1149 | ||
1150 | let atomic_values = &[ | |
1151 | sym::ptr, | |
1152 | sym::integer(8usize), | |
1153 | sym::integer(16usize), | |
1154 | sym::integer(32usize), | |
1155 | sym::integer(64usize), | |
1156 | sym::integer(128usize), | |
1157 | ]; | |
1158 | ||
1159 | let sanitize_values = SanitizerSet::all() | |
1160 | .into_iter() | |
1161 | .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap())); | |
1162 | ||
04454e1e FG |
1163 | // Unknown possible values: |
1164 | // - `feature` | |
1165 | // - `target_feature` | |
1166 | ||
5e7ed085 FG |
1167 | // No-values |
1168 | for name in [ | |
1169 | sym::doc, | |
1170 | sym::miri, | |
1171 | sym::unix, | |
1172 | sym::test, | |
1173 | sym::doctest, | |
1174 | sym::windows, | |
1175 | sym::proc_macro, | |
1176 | sym::debug_assertions, | |
1177 | sym::target_thread_local, | |
1178 | ] { | |
1179 | self.values_valid.entry(name).or_default(); | |
1180 | } | |
1181 | ||
1182 | // Pre-defined values | |
1183 | self.values_valid.entry(sym::panic).or_default().extend(panic_values); | |
1184 | self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values); | |
1185 | self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values); | |
1186 | self.values_valid | |
1187 | .entry(sym::target_has_atomic_load_store) | |
1188 | .or_default() | |
1189 | .extend(atomic_values); | |
1190 | self.values_valid | |
1191 | .entry(sym::target_has_atomic_equal_alignment) | |
1192 | .or_default() | |
1193 | .extend(atomic_values); | |
1194 | ||
1195 | // Target specific values | |
5e7ed085 | 1196 | { |
923072b8 FG |
1197 | const VALUES: [&Symbol; 8] = [ |
1198 | &sym::target_os, | |
1199 | &sym::target_family, | |
1200 | &sym::target_arch, | |
1201 | &sym::target_endian, | |
1202 | &sym::target_env, | |
1203 | &sym::target_abi, | |
1204 | &sym::target_vendor, | |
1205 | &sym::target_pointer_width, | |
1206 | ]; | |
1207 | ||
1208 | // Initialize (if not already initialized) | |
1209 | for &e in VALUES { | |
1210 | self.values_valid.entry(e).or_default(); | |
1211 | } | |
1212 | ||
1213 | // Get all values map at once otherwise it would be costly. | |
1214 | // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). | |
1215 | let [ | |
1216 | values_target_os, | |
1217 | values_target_family, | |
1218 | values_target_arch, | |
1219 | values_target_endian, | |
1220 | values_target_env, | |
1221 | values_target_abi, | |
1222 | values_target_vendor, | |
1223 | values_target_pointer_width, | |
1224 | ] = self | |
1225 | .values_valid | |
1226 | .get_many_mut(VALUES) | |
1227 | .expect("unable to get all the check-cfg values buckets"); | |
1228 | ||
1229 | for target in TARGETS | |
1230 | .iter() | |
1231 | .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) | |
1232 | { | |
1233 | values_target_os.insert(Symbol::intern(&target.options.os)); | |
1234 | values_target_family | |
1235 | .extend(target.options.families.iter().map(|family| Symbol::intern(family))); | |
1236 | values_target_arch.insert(Symbol::intern(&target.arch)); | |
487cf647 | 1237 | values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); |
923072b8 FG |
1238 | values_target_env.insert(Symbol::intern(&target.options.env)); |
1239 | values_target_abi.insert(Symbol::intern(&target.options.abi)); | |
1240 | values_target_vendor.insert(Symbol::intern(&target.options.vendor)); | |
1241 | values_target_pointer_width.insert(sym::integer(target.pointer_width)); | |
1242 | } | |
5e7ed085 FG |
1243 | } |
1244 | } | |
1245 | ||
1246 | pub fn fill_well_known(&mut self) { | |
1247 | self.fill_well_known_names(); | |
1248 | self.fill_well_known_values(); | |
1249 | } | |
5099ac24 FG |
1250 | } |
1251 | ||
60c5eb7d | 1252 | pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig { |
1a4d82fc | 1253 | // Combine the configuration requested by the session (command line) with |
e1599b0c | 1254 | // some default and generated configuration items. |
1a4d82fc | 1255 | let default_cfg = default_configuration(sess); |
e1599b0c | 1256 | // If the user wants a test runner, then add the test cfg. |
1a4d82fc | 1257 | if sess.opts.test { |
dc9dc135 | 1258 | user_cfg.insert((sym::test, None)); |
1a4d82fc | 1259 | } |
476ff2be SL |
1260 | user_cfg.extend(default_cfg.iter().cloned()); |
1261 | user_cfg | |
1a4d82fc JJ |
1262 | } |
1263 | ||
17df50a5 XL |
1264 | pub(super) fn build_target_config( |
1265 | opts: &Options, | |
1266 | target_override: Option<Target>, | |
3c0e092e | 1267 | sysroot: &Path, |
17df50a5 | 1268 | ) -> Target { |
136023e0 XL |
1269 | let target_result = target_override.map_or_else( |
1270 | || Target::search(&opts.target_triple, sysroot), | |
1271 | |t| Ok((t, TargetWarnings::empty())), | |
1272 | ); | |
1273 | let (target, target_warnings) = target_result.unwrap_or_else(|e| { | |
ba9703b0 | 1274 | early_error( |
1b1a35ee | 1275 | opts.error_format, |
ba9703b0 XL |
1276 | &format!( |
1277 | "Error loading target specification: {}. \ | |
cdc7bbd5 | 1278 | Run `rustc --print target-list` for a list of built-in targets", |
ba9703b0 XL |
1279 | e |
1280 | ), | |
1281 | ) | |
0bf4aa26 | 1282 | }); |
136023e0 XL |
1283 | for warning in target_warnings.warning_messages() { |
1284 | early_warn(opts.error_format, &warning) | |
1285 | } | |
1a4d82fc | 1286 | |
29967ef6 XL |
1287 | if !matches!(target.pointer_width, 16 | 32 | 64) { |
1288 | early_error( | |
1b1a35ee | 1289 | opts.error_format, |
ba9703b0 | 1290 | &format!( |
dfeec247 | 1291 | "target specification was invalid: \ |
0531ce1d | 1292 | unrecognized target-pointer-width {}", |
29967ef6 | 1293 | target.pointer_width |
ba9703b0 | 1294 | ), |
29967ef6 XL |
1295 | ) |
1296 | } | |
1a4d82fc | 1297 | |
29967ef6 | 1298 | target |
1a4d82fc JJ |
1299 | } |
1300 | ||
85aaf69f | 1301 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
7453a54e SL |
1302 | pub enum OptionStability { |
1303 | Stable, | |
7453a54e SL |
1304 | Unstable, |
1305 | } | |
1a4d82fc | 1306 | |
1a4d82fc | 1307 | pub struct RustcOptGroup { |
0531ce1d | 1308 | pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>, |
041b39d2 | 1309 | pub name: &'static str, |
1a4d82fc JJ |
1310 | pub stability: OptionStability, |
1311 | } | |
1312 | ||
1313 | impl RustcOptGroup { | |
1314 | pub fn is_stable(&self) -> bool { | |
1315 | self.stability == OptionStability::Stable | |
1316 | } | |
1317 | ||
041b39d2 | 1318 | pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup |
0531ce1d XL |
1319 | where |
1320 | F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, | |
041b39d2 | 1321 | { |
dfeec247 | 1322 | RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable } |
1a4d82fc JJ |
1323 | } |
1324 | ||
041b39d2 | 1325 | pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup |
0531ce1d XL |
1326 | where |
1327 | F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, | |
041b39d2 | 1328 | { |
dfeec247 | 1329 | RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable } |
1a4d82fc JJ |
1330 | } |
1331 | } | |
1332 | ||
1333 | // The `opt` local module holds wrappers around the `getopts` API that | |
1334 | // adds extra rustc-specific metadata to each option; such metadata | |
9c376795 | 1335 | // is exposed by . The public |
1a4d82fc | 1336 | // functions below ending with `_u` are the functions that return |
0731742a | 1337 | // *unstable* options, i.e., options that are only enabled when the |
1a4d82fc JJ |
1338 | // user also passes the `-Z unstable-options` debugging flag. |
1339 | mod opt { | |
416331ca | 1340 | // The `fn flag*` etc below are written so that we can use them |
1a4d82fc JJ |
1341 | // in the future; do not warn about them not being used right now. |
1342 | #![allow(dead_code)] | |
1343 | ||
1a4d82fc JJ |
1344 | use super::RustcOptGroup; |
1345 | ||
c34b1796 | 1346 | pub type R = RustcOptGroup; |
041b39d2 XL |
1347 | pub type S = &'static str; |
1348 | ||
1349 | fn stable<F>(name: S, f: F) -> R | |
0531ce1d XL |
1350 | where |
1351 | F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, | |
041b39d2 XL |
1352 | { |
1353 | RustcOptGroup::stable(name, f) | |
1354 | } | |
1355 | ||
1356 | fn unstable<F>(name: S, f: F) -> R | |
0531ce1d XL |
1357 | where |
1358 | F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, | |
041b39d2 XL |
1359 | { |
1360 | RustcOptGroup::unstable(name, f) | |
1361 | } | |
1a4d82fc | 1362 | |
041b39d2 | 1363 | fn longer(a: S, b: S) -> S { |
dfeec247 | 1364 | if a.len() > b.len() { a } else { b } |
041b39d2 | 1365 | } |
1a4d82fc | 1366 | |
7453a54e | 1367 | pub fn opt_s(a: S, b: S, c: S, d: S) -> R { |
041b39d2 | 1368 | stable(longer(a, b), move |opts| opts.optopt(a, b, c, d)) |
7453a54e SL |
1369 | } |
1370 | pub fn multi_s(a: S, b: S, c: S, d: S) -> R { | |
041b39d2 | 1371 | stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) |
7453a54e SL |
1372 | } |
1373 | pub fn flag_s(a: S, b: S, c: S) -> R { | |
041b39d2 | 1374 | stable(longer(a, b), move |opts| opts.optflag(a, b, c)) |
7453a54e | 1375 | } |
7453a54e | 1376 | pub fn flagmulti_s(a: S, b: S, c: S) -> R { |
041b39d2 | 1377 | stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c)) |
7453a54e | 1378 | } |
d9579d0f | 1379 | |
7453a54e | 1380 | pub fn opt(a: S, b: S, c: S, d: S) -> R { |
041b39d2 | 1381 | unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d)) |
7453a54e SL |
1382 | } |
1383 | pub fn multi(a: S, b: S, c: S, d: S) -> R { | |
041b39d2 | 1384 | unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) |
7453a54e | 1385 | } |
1a4d82fc | 1386 | } |
9c376795 FG |
1387 | static EDITION_STRING: LazyLock<String> = LazyLock::new(|| { |
1388 | format!( | |
1389 | "Specify which edition of the compiler to use when compiling code. \ | |
1390 | The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}." | |
1391 | ) | |
1392 | }); | |
1a4d82fc JJ |
1393 | /// Returns the "short" subset of the rustc command line options, |
1394 | /// including metadata for each option, such as whether the option is | |
1395 | /// part of the stable long-term interface for rustc. | |
1396 | pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { | |
1397 | vec![ | |
7453a54e SL |
1398 | opt::flag_s("h", "help", "Display this message"), |
1399 | opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"), | |
5099ac24 | 1400 | opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"), |
0531ce1d XL |
1401 | opt::multi_s( |
1402 | "L", | |
1403 | "", | |
1404 | "Add a directory to the library search path. The | |
a7813a04 | 1405 | optional KIND can be one of dependency, crate, native, |
416331ca | 1406 | framework, or all (the default).", |
0531ce1d XL |
1407 | "[KIND=]PATH", |
1408 | ), | |
1409 | opt::multi_s( | |
1410 | "l", | |
1411 | "", | |
1412 | "Link the generated crate(s) to the specified native | |
a7813a04 | 1413 | library NAME. The optional KIND can be one of |
17df50a5 XL |
1414 | static, framework, or dylib (the default). |
1415 | Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed) | |
1416 | may be specified each with a prefix of either '+' to | |
1417 | enable or '-' to disable.", | |
1418 | "[KIND[:MODIFIERS]=]NAME[:RENAME]", | |
0531ce1d | 1419 | ), |
e1599b0c | 1420 | make_crate_type_option(), |
dfeec247 | 1421 | opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"), |
532ac7d7 XL |
1422 | opt::opt_s( |
1423 | "", | |
1424 | "edition", | |
9c376795 | 1425 | &*EDITION_STRING, |
532ac7d7 XL |
1426 | EDITION_NAME_LIST, |
1427 | ), | |
0531ce1d XL |
1428 | opt::multi_s( |
1429 | "", | |
1430 | "emit", | |
1431 | "Comma separated list of types of output for \ | |
1432 | the compiler to emit", | |
1433 | "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]", | |
1434 | ), | |
1435 | opt::multi_s( | |
1436 | "", | |
1437 | "print", | |
48663c56 | 1438 | "Compiler information to print on stdout", |
2b03887a FG |
1439 | "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\ |
1440 | target-list|target-cpus|target-features|relocation-models|code-models|\ | |
5099ac24 FG |
1441 | tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\ |
1442 | link-args]", | |
0531ce1d XL |
1443 | ), |
1444 | opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"), | |
7453a54e SL |
1445 | opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"), |
1446 | opt::opt_s("o", "", "Write output to <filename>", "FILENAME"), | |
0531ce1d XL |
1447 | opt::opt_s( |
1448 | "", | |
1449 | "out-dir", | |
1450 | "Write output to compiler-chosen filename \ | |
1451 | in <dir>", | |
1452 | "DIR", | |
1453 | ), | |
1454 | opt::opt_s( | |
1455 | "", | |
1456 | "explain", | |
1457 | "Provide a detailed explanation of an error \ | |
1458 | message", | |
1459 | "OPT", | |
1460 | ), | |
7453a54e | 1461 | opt::flag_s("", "test", "Build a test harness"), |
dfeec247 | 1462 | opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"), |
94222f64 XL |
1463 | opt::multi_s("A", "allow", "Set lint allowed", "LINT"), |
1464 | opt::multi_s("W", "warn", "Set lint warnings", "LINT"), | |
1465 | opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"), | |
1466 | opt::multi_s("D", "deny", "Set lint denied", "LINT"), | |
1467 | opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"), | |
0531ce1d XL |
1468 | opt::multi_s( |
1469 | "", | |
1470 | "cap-lints", | |
1471 | "Set the most restrictive lint level. \ | |
1472 | More restrictive lints are capped at this \ | |
1473 | level", | |
1474 | "LEVEL", | |
1475 | ), | |
7453a54e SL |
1476 | opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"), |
1477 | opt::flag_s("V", "version", "Print version info and exit"), | |
1478 | opt::flag_s("v", "verbose", "Use verbose output"), | |
1a4d82fc JJ |
1479 | ] |
1480 | } | |
1481 | ||
1482 | /// Returns all rustc command line options, including metadata for | |
1483 | /// each option, such as whether the option is part of the stable | |
1484 | /// long-term interface for rustc. | |
1485 | pub fn rustc_optgroups() -> Vec<RustcOptGroup> { | |
1486 | let mut opts = rustc_short_optgroups(); | |
064997fb | 1487 | // FIXME: none of these descriptions are actually used |
041b39d2 | 1488 | opts.extend(vec![ |
0531ce1d XL |
1489 | opt::multi_s( |
1490 | "", | |
1491 | "extern", | |
1492 | "Specify where an external rust library is located", | |
60c5eb7d | 1493 | "NAME[=PATH]", |
9fa01778 | 1494 | ), |
7453a54e | 1495 | opt::opt_s("", "sysroot", "Override the system root", "PATH"), |
064997fb | 1496 | opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"), |
0531ce1d XL |
1497 | opt::opt_s( |
1498 | "", | |
1499 | "error-format", | |
1500 | "How errors and other messages are produced", | |
1501 | "human|json|short", | |
1502 | ), | |
dfeec247 | 1503 | opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"), |
0531ce1d XL |
1504 | opt::opt_s( |
1505 | "", | |
1506 | "color", | |
1507 | "Configure coloring of output: | |
54a0048b SL |
1508 | auto = colorize, if output goes to a tty (default); |
1509 | always = always colorize output; | |
0531ce1d XL |
1510 | never = never colorize output", |
1511 | "auto|always|never", | |
1512 | ), | |
064997fb FG |
1513 | opt::opt_s( |
1514 | "", | |
1515 | "diagnostic-width", | |
1516 | "Inform rustc of the width of the output so that diagnostics can be truncated to fit", | |
1517 | "WIDTH", | |
1518 | ), | |
0531ce1d XL |
1519 | opt::multi_s( |
1520 | "", | |
1521 | "remap-path-prefix", | |
1522 | "Remap source names in all output (compiler messages and output files)", | |
1523 | "FROM=TO", | |
1524 | ), | |
1a4d82fc JJ |
1525 | ]); |
1526 | opts | |
1527 | } | |
1528 | ||
dfeec247 XL |
1529 | pub fn get_cmd_lint_options( |
1530 | matches: &getopts::Matches, | |
1531 | error_format: ErrorOutputType, | |
136023e0 | 1532 | ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) { |
74b04a01 | 1533 | let mut lint_opts_with_position = vec![]; |
8faf50e0 XL |
1534 | let mut describe_lints = false; |
1535 | ||
923072b8 | 1536 | for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] { |
136023e0 | 1537 | for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) { |
8faf50e0 XL |
1538 | if lint_name == "help" { |
1539 | describe_lints = true; | |
1540 | } else { | |
a2a8927a | 1541 | lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level)); |
8faf50e0 XL |
1542 | } |
1543 | } | |
1544 | } | |
1545 | ||
74b04a01 XL |
1546 | lint_opts_with_position.sort_by_key(|x| x.0); |
1547 | let lint_opts = lint_opts_with_position | |
1548 | .iter() | |
1549 | .cloned() | |
1550 | .map(|(_, lint_name, level)| (lint_name, level)) | |
1551 | .collect(); | |
1552 | ||
8faf50e0 XL |
1553 | let lint_cap = matches.opt_str("cap-lints").map(|cap| { |
1554 | lint::Level::from_str(&cap) | |
5e7ed085 | 1555 | .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`"))) |
8faf50e0 | 1556 | }); |
17df50a5 | 1557 | |
136023e0 | 1558 | (lint_opts, describe_lints, lint_cap) |
8faf50e0 XL |
1559 | } |
1560 | ||
e1599b0c | 1561 | /// Parses the `--color` flag. |
416331ca | 1562 | pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { |
487cf647 | 1563 | match matches.opt_str("color").as_deref() { |
0531ce1d | 1564 | Some("auto") => ColorConfig::Auto, |
9cc50fc6 | 1565 | Some("always") => ColorConfig::Always, |
0531ce1d | 1566 | Some("never") => ColorConfig::Never, |
e9174d1e | 1567 | |
9cc50fc6 | 1568 | None => ColorConfig::Auto, |
e9174d1e | 1569 | |
0531ce1d XL |
1570 | Some(arg) => early_error( |
1571 | ErrorOutputType::default(), | |
1572 | &format!( | |
e1599b0c | 1573 | "argument for `--color` must be auto, \ |
5e7ed085 | 1574 | always or never (instead was `{arg}`)" |
0531ce1d XL |
1575 | ), |
1576 | ), | |
416331ca XL |
1577 | } |
1578 | } | |
9cc50fc6 | 1579 | |
cdc7bbd5 XL |
1580 | /// Possible json config files |
1581 | pub struct JsonConfig { | |
1582 | pub json_rendered: HumanReadableErrorType, | |
1583 | pub json_artifact_notifications: bool, | |
04454e1e | 1584 | pub json_unused_externs: JsonUnusedExterns, |
a2a8927a | 1585 | pub json_future_incompat: bool, |
cdc7bbd5 XL |
1586 | } |
1587 | ||
04454e1e FG |
1588 | /// Report unused externs in event stream |
1589 | #[derive(Copy, Clone)] | |
1590 | pub enum JsonUnusedExterns { | |
1591 | /// Do not | |
1592 | No, | |
1593 | /// Report, but do not exit with failure status for deny/forbid | |
1594 | Silent, | |
1595 | /// Report, and also exit with failure status for deny/forbid | |
1596 | Loud, | |
1597 | } | |
1598 | ||
1599 | impl JsonUnusedExterns { | |
1600 | pub fn is_enabled(&self) -> bool { | |
1601 | match self { | |
1602 | JsonUnusedExterns::No => false, | |
1603 | JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true, | |
1604 | } | |
1605 | } | |
1606 | ||
1607 | pub fn is_loud(&self) -> bool { | |
1608 | match self { | |
1609 | JsonUnusedExterns::No | JsonUnusedExterns::Silent => false, | |
1610 | JsonUnusedExterns::Loud => true, | |
1611 | } | |
1612 | } | |
1613 | } | |
1614 | ||
416331ca XL |
1615 | /// Parse the `--json` flag. |
1616 | /// | |
1617 | /// The first value returned is how to render JSON diagnostics, and the second | |
1618 | /// is whether or not artifact notifications are enabled. | |
cdc7bbd5 | 1619 | pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { |
416331ca XL |
1620 | let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType = |
1621 | HumanReadableErrorType::Default; | |
1622 | let mut json_color = ColorConfig::Never; | |
1623 | let mut json_artifact_notifications = false; | |
04454e1e | 1624 | let mut json_unused_externs = JsonUnusedExterns::No; |
a2a8927a | 1625 | let mut json_future_incompat = false; |
416331ca XL |
1626 | for option in matches.opt_strs("json") { |
1627 | // For now conservatively forbid `--color` with `--json` since `--json` | |
1628 | // won't actually be emitting any colors and anything colorized is | |
1629 | // embedded in a diagnostic message anyway. | |
1630 | if matches.opt_str("color").is_some() { | |
0bf4aa26 | 1631 | early_error( |
83c7162d | 1632 | ErrorOutputType::default(), |
416331ca XL |
1633 | "cannot specify the `--color` option with `--json`", |
1634 | ); | |
1635 | } | |
83c7162d | 1636 | |
416331ca XL |
1637 | for sub_option in option.split(',') { |
1638 | match sub_option { | |
1639 | "diagnostic-short" => json_rendered = HumanReadableErrorType::Short, | |
1640 | "diagnostic-rendered-ansi" => json_color = ColorConfig::Always, | |
1641 | "artifacts" => json_artifact_notifications = true, | |
04454e1e FG |
1642 | "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud, |
1643 | "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent, | |
a2a8927a | 1644 | "future-incompat" => json_future_incompat = true, |
dfeec247 XL |
1645 | s => early_error( |
1646 | ErrorOutputType::default(), | |
5e7ed085 | 1647 | &format!("unknown `--json` option `{s}`"), |
dfeec247 | 1648 | ), |
416331ca XL |
1649 | } |
1650 | } | |
83c7162d | 1651 | } |
cdc7bbd5 XL |
1652 | |
1653 | JsonConfig { | |
1654 | json_rendered: json_rendered(json_color), | |
1655 | json_artifact_notifications, | |
1656 | json_unused_externs, | |
a2a8927a | 1657 | json_future_incompat, |
cdc7bbd5 | 1658 | } |
416331ca | 1659 | } |
83c7162d | 1660 | |
e1599b0c | 1661 | /// Parses the `--error-format` flag. |
416331ca XL |
1662 | pub fn parse_error_format( |
1663 | matches: &getopts::Matches, | |
1664 | color: ColorConfig, | |
1665 | json_rendered: HumanReadableErrorType, | |
1666 | ) -> ErrorOutputType { | |
e1599b0c | 1667 | // We need the `opts_present` check because the driver will send us Matches |
9cc50fc6 | 1668 | // with only stable options if no unstable options are used. Since error-format |
e1599b0c XL |
1669 | // is unstable, it will not be present. We have to use `opts_present` not |
1670 | // `opt_present` because the latter will panic. | |
9cc50fc6 | 1671 | let error_format = if matches.opts_present(&["error-format".to_owned()]) { |
487cf647 | 1672 | match matches.opt_str("error-format").as_deref() { |
dfeec247 XL |
1673 | None | Some("human") => { |
1674 | ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)) | |
1675 | } | |
dc9dc135 XL |
1676 | Some("human-annotate-rs") => { |
1677 | ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color)) | |
dfeec247 | 1678 | } |
48663c56 XL |
1679 | Some("json") => ErrorOutputType::Json { pretty: false, json_rendered }, |
1680 | Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered }, | |
1681 | Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)), | |
9cc50fc6 | 1682 | |
0531ce1d | 1683 | Some(arg) => early_error( |
48663c56 | 1684 | ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), |
0531ce1d | 1685 | &format!( |
e1599b0c | 1686 | "argument for `--error-format` must be `human`, `json` or \ |
5e7ed085 | 1687 | `short` (instead was `{arg}`)" |
0531ce1d XL |
1688 | ), |
1689 | ), | |
e9174d1e | 1690 | } |
9cc50fc6 | 1691 | } else { |
48663c56 | 1692 | ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)) |
e9174d1e SL |
1693 | }; |
1694 | ||
416331ca XL |
1695 | match error_format { |
1696 | ErrorOutputType::Json { .. } => {} | |
1697 | ||
1698 | // Conservatively require that the `--json` argument is coupled with | |
1699 | // `--error-format=json`. This means that `--json` is specified we | |
1700 | // should actually be emitting JSON blobs. | |
74b04a01 | 1701 | _ if !matches.opt_strs("json").is_empty() => { |
416331ca XL |
1702 | early_error( |
1703 | ErrorOutputType::default(), | |
1704 | "using `--json` requires also using `--error-format=json`", | |
1705 | ); | |
1706 | } | |
1707 | ||
1708 | _ => {} | |
1709 | } | |
1710 | ||
ba9703b0 | 1711 | error_format |
416331ca XL |
1712 | } |
1713 | ||
5869c6ff | 1714 | pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { |
416331ca | 1715 | let edition = match matches.opt_str("edition") { |
dfeec247 | 1716 | Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| { |
416331ca XL |
1717 | early_error( |
1718 | ErrorOutputType::default(), | |
1719 | &format!( | |
e1599b0c | 1720 | "argument for `--edition` must be one of: \ |
5e7ed085 | 1721 | {EDITION_NAME_LIST}. (instead was `{arg}`)" |
416331ca | 1722 | ), |
dfeec247 XL |
1723 | ) |
1724 | }), | |
416331ca XL |
1725 | None => DEFAULT_EDITION, |
1726 | }; | |
1727 | ||
5869c6ff | 1728 | if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) { |
cdc7bbd5 XL |
1729 | let is_nightly = nightly_options::match_is_nightly_build(matches); |
1730 | let msg = if !is_nightly { | |
1731 | format!( | |
1732 | "the crate requires edition {}, but the latest edition supported by this Rust version is {}", | |
1733 | edition, LATEST_STABLE_EDITION | |
1734 | ) | |
1735 | } else { | |
5e7ed085 | 1736 | format!("edition {edition} is unstable and only available with -Z unstable-options") |
cdc7bbd5 XL |
1737 | }; |
1738 | early_error(ErrorOutputType::default(), &msg) | |
416331ca XL |
1739 | } |
1740 | ||
e74abb32 XL |
1741 | edition |
1742 | } | |
abe05a73 | 1743 | |
064997fb FG |
1744 | fn check_error_format_stability( |
1745 | unstable_opts: &UnstableOptions, | |
e74abb32 XL |
1746 | error_format: ErrorOutputType, |
1747 | json_rendered: HumanReadableErrorType, | |
1748 | ) { | |
064997fb | 1749 | if !unstable_opts.unstable_options { |
48663c56 XL |
1750 | if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format { |
1751 | early_error( | |
1752 | ErrorOutputType::Json { pretty: false, json_rendered }, | |
e1599b0c | 1753 | "`--error-format=pretty-json` is unstable", |
48663c56 XL |
1754 | ); |
1755 | } | |
dc9dc135 | 1756 | if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) = |
dfeec247 XL |
1757 | error_format |
1758 | { | |
dc9dc135 XL |
1759 | early_error( |
1760 | ErrorOutputType::Json { pretty: false, json_rendered }, | |
e1599b0c | 1761 | "`--error-format=human-annotate-rs` is unstable", |
dc9dc135 XL |
1762 | ); |
1763 | } | |
abe05a73 | 1764 | } |
e74abb32 | 1765 | } |
1a4d82fc | 1766 | |
e74abb32 | 1767 | fn parse_output_types( |
064997fb | 1768 | unstable_opts: &UnstableOptions, |
e74abb32 XL |
1769 | matches: &getopts::Matches, |
1770 | error_format: ErrorOutputType, | |
1771 | ) -> OutputTypes { | |
5bcae85e | 1772 | let mut output_types = BTreeMap::new(); |
064997fb | 1773 | if !unstable_opts.parse_only { |
b039eaaf SL |
1774 | for list in matches.opt_strs("emit") { |
1775 | for output_type in list.split(',') { | |
fc512014 XL |
1776 | let (shorthand, path) = match output_type.split_once('=') { |
1777 | None => (output_type, None), | |
1778 | Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))), | |
1779 | }; | |
dfeec247 | 1780 | let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { |
0bf4aa26 | 1781 | early_error( |
0531ce1d XL |
1782 | error_format, |
1783 | &format!( | |
5e7ed085 FG |
1784 | "unknown emission type: `{shorthand}` - expected one of: {display}", |
1785 | display = OutputType::shorthands_display(), | |
0531ce1d | 1786 | ), |
dfeec247 XL |
1787 | ) |
1788 | }); | |
b039eaaf | 1789 | output_types.insert(output_type, path); |
1a4d82fc JJ |
1790 | } |
1791 | } | |
1792 | }; | |
7cac9316 | 1793 | if output_types.is_empty() { |
b039eaaf | 1794 | output_types.insert(OutputType::Exe, None); |
1a4d82fc | 1795 | } |
e74abb32 XL |
1796 | OutputTypes(output_types) |
1797 | } | |
1a4d82fc | 1798 | |
e74abb32 XL |
1799 | fn should_override_cgus_and_disable_thinlto( |
1800 | output_types: &OutputTypes, | |
1801 | matches: &getopts::Matches, | |
1802 | error_format: ErrorOutputType, | |
1803 | mut codegen_units: Option<usize>, | |
1804 | ) -> (bool, Option<usize>) { | |
487cf647 | 1805 | let mut disable_local_thinlto = false; |
e1599b0c | 1806 | // Issue #30063: if user requests LLVM-related output to one |
92a42be0 | 1807 | // particular path, disable codegen-units. |
dfeec247 XL |
1808 | let incompatible: Vec<_> = output_types |
1809 | .0 | |
0531ce1d | 1810 | .iter() |
ea8adc8c | 1811 | .map(|ot_path| ot_path.0) |
0531ce1d | 1812 | .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file()) |
ea8adc8c XL |
1813 | .map(|ot| ot.shorthand()) |
1814 | .collect(); | |
1815 | if !incompatible.is_empty() { | |
1816 | match codegen_units { | |
1817 | Some(n) if n > 1 => { | |
1818 | if matches.opt_present("o") { | |
1819 | for ot in &incompatible { | |
0531ce1d XL |
1820 | early_warn( |
1821 | error_format, | |
1822 | &format!( | |
5e7ed085 | 1823 | "`--emit={ot}` with `-o` incompatible with \ |
e1599b0c | 1824 | `-C codegen-units=N` for N > 1", |
0531ce1d XL |
1825 | ), |
1826 | ); | |
ea8adc8c XL |
1827 | } |
1828 | early_warn(error_format, "resetting to default -C codegen-units=1"); | |
1829 | codegen_units = Some(1); | |
487cf647 | 1830 | disable_local_thinlto = true; |
ea8adc8c | 1831 | } |
92a42be0 | 1832 | } |
ff7c6d11 XL |
1833 | _ => { |
1834 | codegen_units = Some(1); | |
487cf647 | 1835 | disable_local_thinlto = true; |
ff7c6d11 | 1836 | } |
92a42be0 SL |
1837 | } |
1838 | } | |
1839 | ||
e74abb32 | 1840 | if codegen_units == Some(0) { |
dfeec247 | 1841 | early_error(error_format, "value for codegen units must be a positive non-zero integer"); |
ff7c6d11 XL |
1842 | } |
1843 | ||
487cf647 | 1844 | (disable_local_thinlto, codegen_units) |
e74abb32 XL |
1845 | } |
1846 | ||
064997fb FG |
1847 | fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) { |
1848 | if unstable_opts.threads == 0 { | |
dfeec247 | 1849 | early_error(error_format, "value for threads must be a positive non-zero integer"); |
83c7162d XL |
1850 | } |
1851 | ||
064997fb | 1852 | if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() { |
dfeec247 | 1853 | early_error(error_format, "optimization fuel is incompatible with multiple threads"); |
54a0048b | 1854 | } |
e74abb32 | 1855 | } |
54a0048b | 1856 | |
e74abb32 XL |
1857 | fn collect_print_requests( |
1858 | cg: &mut CodegenOptions, | |
064997fb | 1859 | unstable_opts: &mut UnstableOptions, |
e74abb32 | 1860 | matches: &getopts::Matches, |
e74abb32 XL |
1861 | error_format: ErrorOutputType, |
1862 | ) -> Vec<PrintRequest> { | |
5bcae85e SL |
1863 | let mut prints = Vec::<PrintRequest>::new(); |
1864 | if cg.target_cpu.as_ref().map_or(false, |s| s == "help") { | |
1865 | prints.push(PrintRequest::TargetCPUs); | |
1866 | cg.target_cpu = None; | |
1867 | }; | |
1868 | if cg.target_feature == "help" { | |
1869 | prints.push(PrintRequest::TargetFeatures); | |
b7449926 | 1870 | cg.target_feature = String::new(); |
5bcae85e | 1871 | } |
5bcae85e | 1872 | |
487cf647 FG |
1873 | const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[ |
1874 | ("crate-name", PrintRequest::CrateName), | |
1875 | ("file-names", PrintRequest::FileNames), | |
1876 | ("sysroot", PrintRequest::Sysroot), | |
1877 | ("target-libdir", PrintRequest::TargetLibdir), | |
1878 | ("cfg", PrintRequest::Cfg), | |
1879 | ("calling-conventions", PrintRequest::CallingConventions), | |
1880 | ("target-list", PrintRequest::TargetList), | |
1881 | ("target-cpus", PrintRequest::TargetCPUs), | |
1882 | ("target-features", PrintRequest::TargetFeatures), | |
1883 | ("relocation-models", PrintRequest::RelocationModels), | |
1884 | ("code-models", PrintRequest::CodeModels), | |
1885 | ("tls-models", PrintRequest::TlsModels), | |
1886 | ("native-static-libs", PrintRequest::NativeStaticLibs), | |
1887 | ("stack-protector-strategies", PrintRequest::StackProtectorStrategies), | |
1888 | ("target-spec-json", PrintRequest::TargetSpec), | |
1889 | ("link-args", PrintRequest::LinkArgs), | |
1890 | ("split-debuginfo", PrintRequest::SplitDebuginfo), | |
1891 | ]; | |
1892 | ||
1893 | prints.extend(matches.opt_strs("print").into_iter().map(|req| { | |
1894 | match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) { | |
1895 | Some((_, PrintRequest::TargetSpec)) => { | |
1896 | if unstable_opts.unstable_options { | |
1897 | PrintRequest::TargetSpec | |
1898 | } else { | |
1899 | early_error( | |
1900 | error_format, | |
1901 | "the `-Z unstable-options` flag must also be passed to \ | |
1902 | enable the target-spec-json print option", | |
1903 | ); | |
1904 | } | |
1905 | } | |
1906 | Some(&(_, print_request)) => print_request, | |
1907 | None => { | |
1908 | let prints = | |
1909 | PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>(); | |
1910 | let prints = prints.join(", "); | |
e74abb32 XL |
1911 | early_error( |
1912 | error_format, | |
487cf647 | 1913 | &format!("unknown print request `{req}`. Valid print requests are: {prints}"), |
e74abb32 XL |
1914 | ); |
1915 | } | |
1916 | } | |
e74abb32 | 1917 | })); |
1a4d82fc | 1918 | |
e74abb32 XL |
1919 | prints |
1920 | } | |
1921 | ||
17df50a5 XL |
1922 | pub fn parse_target_triple( |
1923 | matches: &getopts::Matches, | |
1924 | error_format: ErrorOutputType, | |
1925 | ) -> TargetTriple { | |
e74abb32 XL |
1926 | match matches.opt_str("target") { |
1927 | Some(target) if target.ends_with(".json") => { | |
0531ce1d | 1928 | let path = Path::new(&target); |
487cf647 | 1929 | TargetTriple::from_path(path).unwrap_or_else(|_| { |
5e7ed085 | 1930 | early_error(error_format, &format!("target file {path:?} does not exist")) |
dfeec247 | 1931 | }) |
e74abb32 | 1932 | } |
6a06907d | 1933 | Some(target) => TargetTriple::TargetTriple(target), |
e74abb32 XL |
1934 | _ => TargetTriple::from_triple(host_triple()), |
1935 | } | |
1936 | } | |
1937 | ||
1938 | fn parse_opt_level( | |
1939 | matches: &getopts::Matches, | |
1940 | cg: &CodegenOptions, | |
1941 | error_format: ErrorOutputType, | |
1942 | ) -> OptLevel { | |
1943 | // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able | |
1944 | // to use them interchangeably. However, because they're technically different flags, | |
1945 | // we need to work out manually which should take precedence if both are supplied (i.e. | |
1946 | // the rightmost flag). We do this by finding the (rightmost) position of both flags and | |
1947 | // comparing them. Note that if a flag is not found, its position will be `None`, which | |
1948 | // always compared less than `Some(_)`. | |
1949 | let max_o = matches.opt_positions("O").into_iter().max(); | |
dfeec247 XL |
1950 | let max_c = matches |
1951 | .opt_strs_pos("C") | |
1952 | .into_iter() | |
fc512014 XL |
1953 | .flat_map(|(i, s)| { |
1954 | // NB: This can match a string without `=`. | |
9c376795 | 1955 | if let Some("opt-level") = s.split('=').next() { Some(i) } else { None } |
fc512014 | 1956 | }) |
dfeec247 | 1957 | .max(); |
e74abb32 XL |
1958 | if max_o > max_c { |
1959 | OptLevel::Default | |
0531ce1d | 1960 | } else { |
ba9703b0 XL |
1961 | match cg.opt_level.as_ref() { |
1962 | "0" => OptLevel::No, | |
1963 | "1" => OptLevel::Less, | |
1964 | "2" => OptLevel::Default, | |
1965 | "3" => OptLevel::Aggressive, | |
1966 | "s" => OptLevel::Size, | |
1967 | "z" => OptLevel::SizeMin, | |
1968 | arg => { | |
e74abb32 XL |
1969 | early_error( |
1970 | error_format, | |
1971 | &format!( | |
1972 | "optimization level needs to be \ | |
5e7ed085 | 1973 | between 0-3, s or z (instead was `{arg}`)" |
e74abb32 XL |
1974 | ), |
1975 | ); | |
1a4d82fc JJ |
1976 | } |
1977 | } | |
e74abb32 XL |
1978 | } |
1979 | } | |
1980 | ||
1981 | fn select_debuginfo( | |
1982 | matches: &getopts::Matches, | |
1983 | cg: &CodegenOptions, | |
1984 | error_format: ErrorOutputType, | |
1985 | ) -> DebugInfo { | |
48663c56 | 1986 | let max_g = matches.opt_positions("g").into_iter().max(); |
dfeec247 XL |
1987 | let max_c = matches |
1988 | .opt_strs_pos("C") | |
1989 | .into_iter() | |
fc512014 XL |
1990 | .flat_map(|(i, s)| { |
1991 | // NB: This can match a string without `=`. | |
9c376795 | 1992 | if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None } |
fc512014 | 1993 | }) |
dfeec247 | 1994 | .max(); |
e74abb32 | 1995 | if max_g > max_c { |
b7449926 | 1996 | DebugInfo::Full |
1a4d82fc JJ |
1997 | } else { |
1998 | match cg.debuginfo { | |
ba9703b0 XL |
1999 | 0 => DebugInfo::None, |
2000 | 1 => DebugInfo::Limited, | |
2001 | 2 => DebugInfo::Full, | |
2002 | arg => { | |
0531ce1d XL |
2003 | early_error( |
2004 | error_format, | |
2005 | &format!( | |
2006 | "debug info level needs to be between \ | |
5e7ed085 | 2007 | 0-2 (instead was `{arg}`)" |
0531ce1d XL |
2008 | ), |
2009 | ); | |
1a4d82fc JJ |
2010 | } |
2011 | } | |
1a4d82fc | 2012 | } |
e74abb32 | 2013 | } |
1a4d82fc | 2014 | |
923072b8 | 2015 | pub(crate) fn parse_assert_incr_state( |
3c0e092e XL |
2016 | opt_assertion: &Option<String>, |
2017 | error_format: ErrorOutputType, | |
2018 | ) -> Option<IncrementalStateAssertion> { | |
2019 | match opt_assertion { | |
2020 | Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded), | |
2021 | Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded), | |
5e7ed085 FG |
2022 | Some(s) => { |
2023 | early_error(error_format, &format!("unexpected incremental state assertion value: {s}")) | |
2024 | } | |
3c0e092e XL |
2025 | None => None, |
2026 | } | |
2027 | } | |
2028 | ||
94222f64 XL |
2029 | fn parse_native_lib_kind( |
2030 | matches: &getopts::Matches, | |
2031 | kind: &str, | |
2032 | error_format: ErrorOutputType, | |
2033 | ) -> (NativeLibKind, Option<bool>) { | |
94222f64 XL |
2034 | let (kind, modifiers) = match kind.split_once(':') { |
2035 | None => (kind, None), | |
2036 | Some((kind, modifiers)) => (kind, Some(modifiers)), | |
2037 | }; | |
2038 | ||
2039 | let kind = match kind { | |
923072b8 | 2040 | "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, |
17df50a5 XL |
2041 | "dylib" => NativeLibKind::Dylib { as_needed: None }, |
2042 | "framework" => NativeLibKind::Framework { as_needed: None }, | |
064997fb FG |
2043 | "link-arg" => { |
2044 | if !nightly_options::is_unstable_enabled(matches) { | |
2045 | let why = if nightly_options::match_is_nightly_build(matches) { | |
2046 | " and only accepted on the nightly compiler" | |
2047 | } else { | |
2048 | ", the `-Z unstable-options` flag must also be passed to use it" | |
2049 | }; | |
2050 | early_error(error_format, &format!("library kind `link-arg` is unstable{why}")) | |
2051 | } | |
2052 | NativeLibKind::LinkArg | |
2053 | } | |
923072b8 | 2054 | _ => early_error( |
17df50a5 | 2055 | error_format, |
064997fb FG |
2056 | &format!( |
2057 | "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg" | |
2058 | ), | |
17df50a5 | 2059 | ), |
94222f64 XL |
2060 | }; |
2061 | match modifiers { | |
2062 | None => (kind, None), | |
5e7ed085 | 2063 | Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches), |
17df50a5 XL |
2064 | } |
2065 | } | |
2066 | ||
2067 | fn parse_native_lib_modifiers( | |
17df50a5 XL |
2068 | mut kind: NativeLibKind, |
2069 | modifiers: &str, | |
e74abb32 | 2070 | error_format: ErrorOutputType, |
5e7ed085 | 2071 | matches: &getopts::Matches, |
17df50a5 XL |
2072 | ) -> (NativeLibKind, Option<bool>) { |
2073 | let mut verbatim = None; | |
2074 | for modifier in modifiers.split(',') { | |
487cf647 | 2075 | let (modifier, value) = match modifier.strip_prefix(['+', '-']) { |
17df50a5 XL |
2076 | Some(m) => (m, modifier.starts_with('+')), |
2077 | None => early_error( | |
2078 | error_format, | |
2079 | "invalid linking modifier syntax, expected '+' or '-' prefix \ | |
923072b8 | 2080 | before one of: bundle, verbatim, whole-archive, as-needed", |
17df50a5 XL |
2081 | ), |
2082 | }; | |
2083 | ||
923072b8 FG |
2084 | let report_unstable_modifier = || { |
2085 | if !nightly_options::is_unstable_enabled(matches) { | |
2086 | let why = if nightly_options::match_is_nightly_build(matches) { | |
2087 | " and only accepted on the nightly compiler" | |
2088 | } else { | |
2089 | ", the `-Z unstable-options` flag must also be passed to use it" | |
2090 | }; | |
2091 | early_error( | |
2092 | error_format, | |
2093 | &format!("linking modifier `{modifier}` is unstable{why}"), | |
2094 | ) | |
2095 | } | |
2096 | }; | |
2097 | let assign_modifier = |dst: &mut Option<bool>| { | |
2098 | if dst.is_some() { | |
2099 | let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); | |
2100 | early_error(error_format, &msg) | |
2101 | } else { | |
2102 | *dst = Some(value); | |
17df50a5 | 2103 | } |
923072b8 FG |
2104 | }; |
2105 | match (modifier, &mut kind) { | |
2106 | ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle), | |
17df50a5 XL |
2107 | ("bundle", _) => early_error( |
2108 | error_format, | |
923072b8 | 2109 | "linking modifier `bundle` is only compatible with `static` linking kind", |
17df50a5 XL |
2110 | ), |
2111 | ||
487cf647 | 2112 | ("verbatim", _) => assign_modifier(&mut verbatim), |
17df50a5 XL |
2113 | |
2114 | ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { | |
923072b8 | 2115 | assign_modifier(whole_archive) |
17df50a5 XL |
2116 | } |
2117 | ("whole-archive", _) => early_error( | |
2118 | error_format, | |
923072b8 | 2119 | "linking modifier `whole-archive` is only compatible with `static` linking kind", |
17df50a5 XL |
2120 | ), |
2121 | ||
2122 | ("as-needed", NativeLibKind::Dylib { as_needed }) | |
2123 | | ("as-needed", NativeLibKind::Framework { as_needed }) => { | |
923072b8 FG |
2124 | report_unstable_modifier(); |
2125 | assign_modifier(as_needed) | |
17df50a5 XL |
2126 | } |
2127 | ("as-needed", _) => early_error( | |
2128 | error_format, | |
923072b8 FG |
2129 | "linking modifier `as-needed` is only compatible with \ |
2130 | `dylib` and `framework` linking kinds", | |
17df50a5 XL |
2131 | ), |
2132 | ||
5e7ed085 FG |
2133 | // Note: this error also excludes the case with empty modifier |
2134 | // string, like `modifiers = ""`. | |
17df50a5 XL |
2135 | _ => early_error( |
2136 | error_format, | |
2137 | &format!( | |
923072b8 FG |
2138 | "unknown linking modifier `{modifier}`, expected one \ |
2139 | of: bundle, verbatim, whole-archive, as-needed" | |
17df50a5 XL |
2140 | ), |
2141 | ), | |
2142 | } | |
2143 | } | |
2144 | ||
2145 | (kind, verbatim) | |
2146 | } | |
2147 | ||
2148 | fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> { | |
e74abb32 | 2149 | matches |
0531ce1d XL |
2150 | .opt_strs("l") |
2151 | .into_iter() | |
2152 | .map(|s| { | |
17df50a5 | 2153 | // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]", |
064997fb | 2154 | // where KIND is one of "dylib", "framework", "static", "link-arg" and |
9c376795 | 2155 | // where MODIFIERS are a comma separated list of supported modifiers |
17df50a5 XL |
2156 | // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed |
2157 | // with either + or - to indicate whether it is enabled or disabled. | |
2158 | // The last value specified for a given modifier wins. | |
2159 | let (name, kind, verbatim) = match s.split_once('=') { | |
2160 | None => (s, NativeLibKind::Unspecified, None), | |
fc512014 | 2161 | Some((kind, name)) => { |
94222f64 | 2162 | let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format); |
17df50a5 | 2163 | (name.to_string(), kind, verbatim) |
0531ce1d XL |
2164 | } |
2165 | }; | |
17df50a5 | 2166 | |
fc512014 XL |
2167 | let (name, new_name) = match name.split_once(':') { |
2168 | None => (name, None), | |
2169 | Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), | |
2170 | }; | |
923072b8 FG |
2171 | if name.is_empty() { |
2172 | early_error(error_format, "library name must not be empty"); | |
2173 | } | |
17df50a5 | 2174 | NativeLib { name, new_name, kind, verbatim } |
0531ce1d | 2175 | }) |
e74abb32 XL |
2176 | .collect() |
2177 | } | |
1a4d82fc | 2178 | |
60c5eb7d | 2179 | pub fn parse_externs( |
e74abb32 | 2180 | matches: &getopts::Matches, |
064997fb | 2181 | unstable_opts: &UnstableOptions, |
e74abb32 | 2182 | error_format: ErrorOutputType, |
e74abb32 | 2183 | ) -> Externs { |
064997fb | 2184 | let is_unstable_enabled = unstable_opts.unstable_options; |
48663c56 | 2185 | let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new(); |
60c5eb7d | 2186 | for arg in matches.opt_strs("extern") { |
fc512014 XL |
2187 | let (name, path) = match arg.split_once('=') { |
2188 | None => (arg, None), | |
5869c6ff | 2189 | Some((name, path)) => (name.to_string(), Some(Path::new(path))), |
fc512014 XL |
2190 | }; |
2191 | let (options, name) = match name.split_once(':') { | |
2192 | None => (None, name), | |
2193 | Some((opts, name)) => (Some(opts), name.to_string()), | |
1a4d82fc JJ |
2194 | }; |
2195 | ||
5869c6ff XL |
2196 | let path = path.map(|p| CanonicalizedPath::new(p)); |
2197 | ||
60c5eb7d | 2198 | let entry = externs.entry(name.to_owned()); |
48663c56 | 2199 | |
60c5eb7d | 2200 | use std::collections::btree_map::Entry; |
48663c56 | 2201 | |
60c5eb7d XL |
2202 | let entry = if let Some(path) = path { |
2203 | // --extern prelude_name=some_file.rlib | |
2204 | match entry { | |
2205 | Entry::Vacant(vacant) => { | |
2206 | let files = BTreeSet::from_iter(iter::once(path)); | |
2207 | vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files))) | |
2208 | } | |
2209 | Entry::Occupied(occupied) => { | |
2210 | let ext_ent = occupied.into_mut(); | |
2211 | match ext_ent { | |
2212 | ExternEntry { location: ExternLocation::ExactPaths(files), .. } => { | |
2213 | files.insert(path); | |
2214 | } | |
2215 | ExternEntry { | |
2216 | location: location @ ExternLocation::FoundInLibrarySearchDirectories, | |
2217 | .. | |
2218 | } => { | |
2219 | // Exact paths take precedence over search directories. | |
2220 | let files = BTreeSet::from_iter(iter::once(path)); | |
2221 | *location = ExternLocation::ExactPaths(files); | |
2222 | } | |
2223 | } | |
2224 | ext_ent | |
2225 | } | |
2226 | } | |
2227 | } else { | |
2228 | // --extern prelude_name | |
2229 | match entry { | |
2230 | Entry::Vacant(vacant) => { | |
2231 | vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories)) | |
2232 | } | |
2233 | Entry::Occupied(occupied) => { | |
2234 | // Ignore if already specified. | |
2235 | occupied.into_mut() | |
2236 | } | |
2237 | } | |
2238 | }; | |
2239 | ||
2240 | let mut is_private_dep = false; | |
2241 | let mut add_prelude = true; | |
04454e1e | 2242 | let mut nounused_dep = false; |
60c5eb7d XL |
2243 | if let Some(opts) = options { |
2244 | if !is_unstable_enabled { | |
2245 | early_error( | |
2246 | error_format, | |
2247 | "the `-Z unstable-options` flag must also be passed to \ | |
9ffffee4 | 2248 | enable `--extern` options", |
60c5eb7d XL |
2249 | ); |
2250 | } | |
2251 | for opt in opts.split(',') { | |
2252 | match opt { | |
2253 | "priv" => is_private_dep = true, | |
2254 | "noprelude" => { | |
2255 | if let ExternLocation::ExactPaths(_) = &entry.location { | |
2256 | add_prelude = false; | |
2257 | } else { | |
2258 | early_error( | |
2259 | error_format, | |
2260 | "the `noprelude` --extern option requires a file path", | |
2261 | ); | |
2262 | } | |
2263 | } | |
04454e1e | 2264 | "nounused" => nounused_dep = true, |
5e7ed085 | 2265 | _ => early_error(error_format, &format!("unknown --extern option `{opt}`")), |
60c5eb7d XL |
2266 | } |
2267 | } | |
2268 | } | |
48663c56 | 2269 | |
60c5eb7d XL |
2270 | // Crates start out being not private, and go to being private `priv` |
2271 | // is specified. | |
2272 | entry.is_private_dep |= is_private_dep; | |
04454e1e FG |
2273 | // likewise `nounused` |
2274 | entry.nounused_dep |= nounused_dep; | |
60c5eb7d XL |
2275 | // If any flag is missing `noprelude`, then add to the prelude. |
2276 | entry.add_prelude |= add_prelude; | |
1a4d82fc | 2277 | } |
e74abb32 XL |
2278 | Externs(externs) |
2279 | } | |
1a4d82fc | 2280 | |
e74abb32 XL |
2281 | fn parse_remap_path_prefix( |
2282 | matches: &getopts::Matches, | |
064997fb | 2283 | unstable_opts: &UnstableOptions, |
dfeec247 | 2284 | error_format: ErrorOutputType, |
e74abb32 | 2285 | ) -> Vec<(PathBuf, PathBuf)> { |
c295e0f8 | 2286 | let mut mapping: Vec<(PathBuf, PathBuf)> = matches |
0531ce1d XL |
2287 | .opt_strs("remap-path-prefix") |
2288 | .into_iter() | |
fc512014 XL |
2289 | .map(|remap| match remap.rsplit_once('=') { |
2290 | None => early_error( | |
2291 | error_format, | |
2292 | "--remap-path-prefix must contain '=' between FROM and TO", | |
2293 | ), | |
2294 | Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), | |
0531ce1d | 2295 | }) |
c295e0f8 | 2296 | .collect(); |
064997fb | 2297 | match &unstable_opts.remap_cwd_prefix { |
c295e0f8 XL |
2298 | Some(to) => match std::env::current_dir() { |
2299 | Ok(cwd) => mapping.push((cwd, to.clone())), | |
2300 | Err(_) => (), | |
2301 | }, | |
2302 | None => (), | |
2303 | }; | |
2304 | mapping | |
e74abb32 | 2305 | } |
0531ce1d | 2306 | |
064997fb | 2307 | // JUSTIFICATION: before wrapper fn is available |
f2b60f7d | 2308 | #[allow(rustc::bad_opt_access)] |
e74abb32 XL |
2309 | pub fn build_session_options(matches: &getopts::Matches) -> Options { |
2310 | let color = parse_color(matches); | |
2311 | ||
2312 | let edition = parse_crate_edition(matches); | |
2313 | ||
a2a8927a XL |
2314 | let JsonConfig { |
2315 | json_rendered, | |
2316 | json_artifact_notifications, | |
2317 | json_unused_externs, | |
2318 | json_future_incompat, | |
2319 | } = parse_json(matches); | |
e74abb32 XL |
2320 | |
2321 | let error_format = parse_error_format(matches, color, json_rendered); | |
2322 | ||
064997fb FG |
2323 | let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| { |
2324 | early_error(error_format, "`--diagnostic-width` must be an positive integer"); | |
2325 | }); | |
2326 | ||
e74abb32 XL |
2327 | let unparsed_crate_types = matches.opt_strs("crate-type"); |
2328 | let crate_types = parse_crate_types_from_list(unparsed_crate_types) | |
a2a8927a | 2329 | .unwrap_or_else(|e| early_error(error_format, &e)); |
e74abb32 | 2330 | |
064997fb | 2331 | let mut unstable_opts = UnstableOptions::build(matches, error_format); |
94222f64 | 2332 | let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); |
e74abb32 | 2333 | |
064997fb | 2334 | check_error_format_stability(&unstable_opts, error_format, json_rendered); |
e74abb32 | 2335 | |
064997fb | 2336 | if !unstable_opts.unstable_options && json_unused_externs.is_enabled() { |
cdc7bbd5 XL |
2337 | early_error( |
2338 | error_format, | |
2339 | "the `-Z unstable-options` flag must also be passed to enable \ | |
2340 | the flag `--json=unused-externs`", | |
2341 | ); | |
2342 | } | |
2343 | ||
064997fb | 2344 | let output_types = parse_output_types(&unstable_opts, matches, error_format); |
e74abb32 | 2345 | |
17df50a5 | 2346 | let mut cg = CodegenOptions::build(matches, error_format); |
487cf647 | 2347 | let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto( |
e74abb32 XL |
2348 | &output_types, |
2349 | matches, | |
2350 | error_format, | |
2351 | cg.codegen_units, | |
2352 | ); | |
2353 | ||
064997fb | 2354 | check_thread_count(&unstable_opts, error_format); |
e74abb32 | 2355 | |
5099ac24 | 2356 | let incremental = cg.incremental.as_ref().map(PathBuf::from); |
e74abb32 | 2357 | |
064997fb | 2358 | let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format); |
3c0e092e | 2359 | |
064997fb | 2360 | if unstable_opts.profile && incremental.is_some() { |
e74abb32 | 2361 | early_error( |
0531ce1d | 2362 | error_format, |
e74abb32 XL |
2363 | "can't instrument with gcov profiling when compiling incrementally", |
2364 | ); | |
2365 | } | |
064997fb | 2366 | if unstable_opts.profile { |
ba9703b0 XL |
2367 | match codegen_units { |
2368 | Some(1) => {} | |
2369 | None => codegen_units = Some(1), | |
2370 | Some(_) => early_error( | |
2371 | error_format, | |
2372 | "can't instrument with gcov profiling with multiple codegen units", | |
2373 | ), | |
2374 | } | |
2375 | } | |
e74abb32 XL |
2376 | |
2377 | if cg.profile_generate.enabled() && cg.profile_use.is_some() { | |
2378 | early_error( | |
2379 | error_format, | |
2380 | "options `-C profile-generate` and `-C profile-use` are exclusive", | |
2381 | ); | |
2382 | } | |
2383 | ||
064997fb | 2384 | if unstable_opts.profile_sample_use.is_some() |
c295e0f8 XL |
2385 | && (cg.profile_generate.enabled() || cg.profile_use.is_some()) |
2386 | { | |
2387 | early_error( | |
2388 | error_format, | |
2389 | "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`", | |
2390 | ); | |
2391 | } | |
2392 | ||
a2a8927a XL |
2393 | // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes |
2394 | // precedence. | |
064997fb | 2395 | match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) { |
a2a8927a XL |
2396 | (Some(smv_c), Some(smv_z)) if smv_c != smv_z => { |
2397 | early_error( | |
2398 | error_format, | |
2399 | "incompatible values passed for `-C symbol-mangling-version` \ | |
2400 | and `-Z symbol-mangling-version`", | |
2401 | ); | |
2402 | } | |
2403 | (Some(SymbolManglingVersion::V0), _) => {} | |
064997fb | 2404 | (Some(_), _) if !unstable_opts.unstable_options => { |
a2a8927a XL |
2405 | early_error( |
2406 | error_format, | |
2407 | "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`", | |
2408 | ); | |
2409 | } | |
2410 | (None, None) => {} | |
2411 | (None, smv) => { | |
2412 | early_warn( | |
2413 | error_format, | |
2414 | "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`", | |
2415 | ); | |
2416 | cg.symbol_mangling_version = smv; | |
2417 | } | |
2418 | _ => {} | |
2419 | } | |
2420 | ||
5099ac24 FG |
2421 | // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes |
2422 | // precedence. | |
064997fb | 2423 | match (cg.instrument_coverage, unstable_opts.instrument_coverage) { |
5099ac24 FG |
2424 | (Some(ic_c), Some(ic_z)) if ic_c != ic_z => { |
2425 | early_error( | |
2426 | error_format, | |
2427 | "incompatible values passed for `-C instrument-coverage` \ | |
2428 | and `-Z instrument-coverage`", | |
2429 | ); | |
2430 | } | |
2431 | (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {} | |
064997fb | 2432 | (Some(_), _) if !unstable_opts.unstable_options => { |
5099ac24 FG |
2433 | early_error( |
2434 | error_format, | |
2435 | "`-C instrument-coverage=except-*` requires `-Z unstable-options`", | |
2436 | ); | |
2437 | } | |
2438 | (None, None) => {} | |
2439 | (None, ic) => { | |
2440 | early_warn( | |
2441 | error_format, | |
2442 | "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`", | |
2443 | ); | |
2444 | cg.instrument_coverage = ic; | |
2445 | } | |
2446 | _ => {} | |
2447 | } | |
2448 | ||
2449 | if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) { | |
3dfed10e XL |
2450 | if cg.profile_generate.enabled() || cg.profile_use.is_some() { |
2451 | early_error( | |
2452 | error_format, | |
5099ac24 | 2453 | "option `-C instrument-coverage` is not compatible with either `-C profile-use` \ |
3dfed10e XL |
2454 | or `-C profile-generate`", |
2455 | ); | |
2456 | } | |
2457 | ||
5099ac24 | 2458 | // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent |
1b1a35ee XL |
2459 | // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over |
2460 | // multiple runs, including some changes to source code; so mangled names must be consistent | |
2461 | // across compilations. | |
a2a8927a XL |
2462 | match cg.symbol_mangling_version { |
2463 | None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0), | |
fc512014 XL |
2464 | Some(SymbolManglingVersion::Legacy) => { |
2465 | early_warn( | |
2466 | error_format, | |
5099ac24 | 2467 | "-C instrument-coverage requires symbol mangling version `v0`, \ |
a2a8927a | 2468 | but `-C symbol-mangling-version=legacy` was specified", |
fc512014 XL |
2469 | ); |
2470 | } | |
2471 | Some(SymbolManglingVersion::V0) => {} | |
2472 | } | |
1b1a35ee XL |
2473 | } |
2474 | ||
2475 | if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { | |
064997fb | 2476 | unstable_opts.graphviz_font = graphviz_font; |
3dfed10e XL |
2477 | } |
2478 | ||
f9f354fc XL |
2479 | if !cg.embed_bitcode { |
2480 | match cg.lto { | |
2481 | LtoCli::No | LtoCli::Unspecified => {} | |
2482 | LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error( | |
2483 | error_format, | |
2484 | "options `-C embed-bitcode=no` and `-C lto` are incompatible", | |
2485 | ), | |
2486 | } | |
2487 | } | |
2488 | ||
064997fb | 2489 | let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format); |
e74abb32 XL |
2490 | |
2491 | let cg = cg; | |
2492 | ||
2493 | let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); | |
2494 | let target_triple = parse_target_triple(matches, error_format); | |
2495 | let opt_level = parse_opt_level(matches, &cg, error_format); | |
2496 | // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able | |
2497 | // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`) | |
2498 | // for more details. | |
2499 | let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No); | |
2500 | let debuginfo = select_debuginfo(matches, &cg, error_format); | |
2501 | ||
2502 | let mut search_paths = vec![]; | |
2503 | for s in &matches.opt_strs("L") { | |
487cf647 | 2504 | search_paths.push(SearchPath::from_cli_opt(s, error_format)); |
e74abb32 XL |
2505 | } |
2506 | ||
2507 | let libs = parse_libs(matches, error_format); | |
2508 | ||
2509 | let test = matches.opt_present("test"); | |
2510 | ||
e74abb32 | 2511 | if !cg.remark.is_empty() && debuginfo == DebugInfo::None { |
dfeec247 | 2512 | early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations"); |
e74abb32 XL |
2513 | } |
2514 | ||
064997fb | 2515 | let externs = parse_externs(matches, &unstable_opts, error_format); |
e74abb32 XL |
2516 | |
2517 | let crate_name = matches.opt_str("crate-name"); | |
2518 | ||
064997fb | 2519 | let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format); |
e74abb32 | 2520 | |
064997fb | 2521 | let pretty = parse_pretty(&unstable_opts, error_format); |
60c5eb7d | 2522 | |
9c376795 FG |
2523 | // query-dep-graph is required if dump-dep-graph is given #106736 |
2524 | if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph { | |
2525 | early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`"); | |
2526 | } | |
2527 | ||
cdc7bbd5 XL |
2528 | // Try to find a directory containing the Rust `src`, for more details see |
2529 | // the doc comment on the `real_rust_source_base_dir` field. | |
2530 | let tmp_buf; | |
2531 | let sysroot = match &sysroot_opt { | |
2532 | Some(s) => s, | |
2533 | None => { | |
487cf647 | 2534 | tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot"); |
cdc7bbd5 XL |
2535 | &tmp_buf |
2536 | } | |
2537 | }; | |
2538 | let real_rust_source_base_dir = { | |
2539 | // This is the location used by the `rust-src` `rustup` component. | |
2540 | let mut candidate = sysroot.join("lib/rustlib/src/rust"); | |
2541 | if let Ok(metadata) = candidate.symlink_metadata() { | |
2542 | // Replace the symlink rustbuild creates, with its destination. | |
2543 | // We could try to use `fs::canonicalize` instead, but that might | |
2544 | // produce unnecessarily verbose path. | |
2545 | if metadata.file_type().is_symlink() { | |
2546 | if let Ok(symlink_dest) = std::fs::read_link(&candidate) { | |
2547 | candidate = symlink_dest; | |
2548 | } | |
2549 | } | |
2550 | } | |
2551 | ||
2552 | // Only use this directory if it has a file we can expect to always find. | |
9ffffee4 | 2553 | candidate.join("library/std/src/lib.rs").is_file().then_some(candidate) |
cdc7bbd5 XL |
2554 | }; |
2555 | ||
94222f64 | 2556 | let working_dir = std::env::current_dir().unwrap_or_else(|e| { |
5e7ed085 | 2557 | early_error(error_format, &format!("Current directory is invalid: {e}")); |
94222f64 XL |
2558 | }); |
2559 | ||
9c376795 FG |
2560 | let remap = FilePathMapping::new(remap_path_prefix.clone()); |
2561 | let (path, remapped) = remap.map_prefix(&working_dir); | |
94222f64 | 2562 | let working_dir = if remapped { |
9c376795 | 2563 | RealFileName::Remapped { virtual_name: path.into_owned(), local_path: Some(working_dir) } |
94222f64 | 2564 | } else { |
9c376795 | 2565 | RealFileName::LocalPath(path.into_owned()) |
94222f64 XL |
2566 | }; |
2567 | ||
e74abb32 | 2568 | Options { |
3c0e092e | 2569 | assert_incr_state, |
e74abb32 XL |
2570 | crate_types, |
2571 | optimize: opt_level, | |
2572 | debuginfo, | |
2573 | lint_opts, | |
2574 | lint_cap, | |
2575 | describe_lints, | |
2576 | output_types, | |
2577 | search_paths, | |
2578 | maybe_sysroot: sysroot_opt, | |
2579 | target_triple, | |
2580 | test, | |
2581 | incremental, | |
064997fb | 2582 | unstable_opts, |
e74abb32 | 2583 | prints, |
e74abb32 XL |
2584 | cg, |
2585 | error_format, | |
064997fb | 2586 | diagnostic_width, |
e74abb32 | 2587 | externs, |
fc512014 | 2588 | unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()), |
e74abb32 | 2589 | crate_name, |
e74abb32 | 2590 | libs, |
e74abb32 XL |
2591 | debug_assertions, |
2592 | actually_rustdoc: false, | |
9ffffee4 | 2593 | resolve_doc_links: ResolveDocLinks::ExportedMetadata, |
1b1a35ee | 2594 | trimmed_def_paths: TrimmedDefPaths::default(), |
e74abb32 | 2595 | cli_forced_codegen_units: codegen_units, |
487cf647 | 2596 | cli_forced_local_thinlto_off: disable_local_thinlto, |
e74abb32 | 2597 | remap_path_prefix, |
cdc7bbd5 | 2598 | real_rust_source_base_dir, |
e74abb32 XL |
2599 | edition, |
2600 | json_artifact_notifications, | |
cdc7bbd5 | 2601 | json_unused_externs, |
a2a8927a | 2602 | json_future_incompat, |
60c5eb7d | 2603 | pretty, |
94222f64 XL |
2604 | working_dir, |
2605 | } | |
2606 | } | |
2607 | ||
064997fb | 2608 | fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> { |
94222f64 XL |
2609 | use PpMode::*; |
2610 | ||
064997fb | 2611 | let first = match unstable_opts.unpretty.as_deref()? { |
94222f64 XL |
2612 | "normal" => Source(PpSourceMode::Normal), |
2613 | "identified" => Source(PpSourceMode::Identified), | |
94222f64 XL |
2614 | "expanded" => Source(PpSourceMode::Expanded), |
2615 | "expanded,identified" => Source(PpSourceMode::ExpandedIdentified), | |
2616 | "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene), | |
2617 | "ast-tree" => AstTree(PpAstTreeMode::Normal), | |
2618 | "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded), | |
2619 | "hir" => Hir(PpHirMode::Normal), | |
2620 | "hir,identified" => Hir(PpHirMode::Identified), | |
2621 | "hir,typed" => Hir(PpHirMode::Typed), | |
2622 | "hir-tree" => HirTree, | |
2623 | "thir-tree" => ThirTree, | |
9ffffee4 | 2624 | "thir-flat" => ThirFlat, |
94222f64 XL |
2625 | "mir" => Mir, |
2626 | "mir-cfg" => MirCFG, | |
2627 | name => early_error( | |
2628 | efmt, | |
2629 | &format!( | |
5e7ed085 FG |
2630 | "argument to `unpretty` must be one of `normal`, `identified`, \ |
2631 | `expanded`, `expanded,identified`, `expanded,hygiene`, \ | |
94222f64 | 2632 | `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ |
9ffffee4 FG |
2633 | `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \ |
2634 | `mir-cfg`; got {name}" | |
94222f64 XL |
2635 | ), |
2636 | ), | |
2637 | }; | |
f2b60f7d | 2638 | debug!("got unpretty option: {first:?}"); |
94222f64 | 2639 | Some(first) |
85aaf69f SL |
2640 | } |
2641 | ||
e1599b0c XL |
2642 | pub fn make_crate_type_option() -> RustcOptGroup { |
2643 | opt::multi_s( | |
2644 | "", | |
2645 | "crate-type", | |
2646 | "Comma separated list of types of crates | |
2647 | for the compiler to emit", | |
2648 | "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]", | |
2649 | ) | |
2650 | } | |
2651 | ||
0531ce1d | 2652 | pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> { |
1a4d82fc | 2653 | let mut crate_types: Vec<CrateType> = Vec::new(); |
85aaf69f | 2654 | for unparsed_crate_type in &list_list { |
1a4d82fc JJ |
2655 | for part in unparsed_crate_type.split(',') { |
2656 | let new_part = match part { | |
0531ce1d | 2657 | "lib" => default_lib_output(), |
b7449926 XL |
2658 | "rlib" => CrateType::Rlib, |
2659 | "staticlib" => CrateType::Staticlib, | |
2660 | "dylib" => CrateType::Dylib, | |
2661 | "cdylib" => CrateType::Cdylib, | |
2662 | "bin" => CrateType::Executable, | |
2663 | "proc-macro" => CrateType::ProcMacro, | |
5e7ed085 | 2664 | _ => return Err(format!("unknown crate type: `{part}`")), |
1a4d82fc | 2665 | }; |
85aaf69f SL |
2666 | if !crate_types.contains(&new_part) { |
2667 | crate_types.push(new_part) | |
2668 | } | |
1a4d82fc JJ |
2669 | } |
2670 | } | |
2671 | ||
7cac9316 | 2672 | Ok(crate_types) |
1a4d82fc JJ |
2673 | } |
2674 | ||
54a0048b | 2675 | pub mod nightly_options { |
9e0c209e | 2676 | use super::{ErrorOutputType, OptionStability, RustcOptGroup}; |
60c5eb7d | 2677 | use crate::early_error; |
dfeec247 | 2678 | use rustc_feature::UnstableFeatures; |
54a0048b SL |
2679 | |
2680 | pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { | |
fc512014 XL |
2681 | match_is_nightly_build(matches) |
2682 | && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") | |
2683 | } | |
2684 | ||
2685 | pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool { | |
2686 | is_nightly_build(matches.opt_str("crate-name").as_deref()) | |
54a0048b SL |
2687 | } |
2688 | ||
fc512014 XL |
2689 | pub fn is_nightly_build(krate: Option<&str>) -> bool { |
2690 | UnstableFeatures::from_environment(krate).is_nightly_build() | |
54a0048b SL |
2691 | } |
2692 | ||
2693 | pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) { | |
dfeec247 | 2694 | let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options"); |
fc512014 | 2695 | let really_allows_unstable_options = match_is_nightly_build(matches); |
54a0048b SL |
2696 | |
2697 | for opt in flags.iter() { | |
2698 | if opt.stability == OptionStability::Stable { | |
0531ce1d | 2699 | continue; |
54a0048b | 2700 | } |
041b39d2 | 2701 | if !matches.opt_present(opt.name) { |
0531ce1d | 2702 | continue; |
54a0048b | 2703 | } |
041b39d2 | 2704 | if opt.name != "Z" && !has_z_unstable_option { |
0531ce1d XL |
2705 | early_error( |
2706 | ErrorOutputType::default(), | |
2707 | &format!( | |
2708 | "the `-Z unstable-options` flag must also be passed to enable \ | |
2709 | the flag `{}`", | |
2710 | opt.name | |
2711 | ), | |
2712 | ); | |
54a0048b SL |
2713 | } |
2714 | if really_allows_unstable_options { | |
0531ce1d | 2715 | continue; |
54a0048b SL |
2716 | } |
2717 | match opt.stability { | |
2718 | OptionStability::Unstable => { | |
0531ce1d XL |
2719 | let msg = format!( |
2720 | "the option `{}` is only accepted on the \ | |
2721 | nightly compiler", | |
2722 | opt.name | |
2723 | ); | |
54a0048b SL |
2724 | early_error(ErrorOutputType::default(), &msg); |
2725 | } | |
54a0048b SL |
2726 | OptionStability::Stable => {} |
2727 | } | |
2728 | } | |
2729 | } | |
2730 | } | |
2731 | ||
85aaf69f | 2732 | impl fmt::Display for CrateType { |
0bf4aa26 | 2733 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1a4d82fc | 2734 | match *self { |
b7449926 XL |
2735 | CrateType::Executable => "bin".fmt(f), |
2736 | CrateType::Dylib => "dylib".fmt(f), | |
2737 | CrateType::Rlib => "rlib".fmt(f), | |
2738 | CrateType::Staticlib => "staticlib".fmt(f), | |
2739 | CrateType::Cdylib => "cdylib".fmt(f), | |
2740 | CrateType::ProcMacro => "proc-macro".fmt(f), | |
1a4d82fc JJ |
2741 | } |
2742 | } | |
2743 | } | |
2744 | ||
9ffffee4 FG |
2745 | impl IntoDiagnosticArg for CrateType { |
2746 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
2747 | self.to_string().into_diagnostic_arg() | |
2748 | } | |
2749 | } | |
2750 | ||
60c5eb7d XL |
2751 | #[derive(Copy, Clone, PartialEq, Debug)] |
2752 | pub enum PpSourceMode { | |
94222f64 | 2753 | /// `-Zunpretty=normal` |
6a06907d | 2754 | Normal, |
94222f64 | 2755 | /// `-Zunpretty=expanded` |
6a06907d | 2756 | Expanded, |
94222f64 | 2757 | /// `-Zunpretty=identified` |
6a06907d | 2758 | Identified, |
94222f64 | 2759 | /// `-Zunpretty=expanded,identified` |
6a06907d | 2760 | ExpandedIdentified, |
94222f64 | 2761 | /// `-Zunpretty=expanded,hygiene` |
6a06907d XL |
2762 | ExpandedHygiene, |
2763 | } | |
2764 | ||
2765 | #[derive(Copy, Clone, PartialEq, Debug)] | |
2766 | pub enum PpAstTreeMode { | |
2767 | /// `-Zunpretty=ast` | |
2768 | Normal, | |
2769 | /// `-Zunpretty=ast,expanded` | |
2770 | Expanded, | |
2771 | } | |
2772 | ||
2773 | #[derive(Copy, Clone, PartialEq, Debug)] | |
2774 | pub enum PpHirMode { | |
2775 | /// `-Zunpretty=hir` | |
2776 | Normal, | |
2777 | /// `-Zunpretty=hir,identified` | |
2778 | Identified, | |
2779 | /// `-Zunpretty=hir,typed` | |
2780 | Typed, | |
60c5eb7d XL |
2781 | } |
2782 | ||
2783 | #[derive(Copy, Clone, PartialEq, Debug)] | |
2784 | pub enum PpMode { | |
6a06907d | 2785 | /// Options that print the source code, i.e. |
5e7ed085 | 2786 | /// `-Zunpretty=normal` and `-Zunpretty=expanded` |
6a06907d XL |
2787 | Source(PpSourceMode), |
2788 | AstTree(PpAstTreeMode), | |
2789 | /// Options that print the HIR, i.e. `-Zunpretty=hir` | |
2790 | Hir(PpHirMode), | |
2791 | /// `-Zunpretty=hir-tree` | |
2792 | HirTree, | |
2793 | /// `-Zunpretty=thir-tree` | |
2794 | ThirTree, | |
9ffffee4 FG |
2795 | /// `-Zunpretty=thir-flat` |
2796 | ThirFlat, | |
6a06907d XL |
2797 | /// `-Zunpretty=mir` |
2798 | Mir, | |
2799 | /// `-Zunpretty=mir-cfg` | |
2800 | MirCFG, | |
60c5eb7d XL |
2801 | } |
2802 | ||
2803 | impl PpMode { | |
2804 | pub fn needs_ast_map(&self) -> bool { | |
2805 | use PpMode::*; | |
2806 | use PpSourceMode::*; | |
2807 | match *self { | |
6a06907d XL |
2808 | Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false, |
2809 | ||
5e7ed085 | 2810 | Source(Expanded | ExpandedIdentified | ExpandedHygiene) |
6a06907d XL |
2811 | | AstTree(PpAstTreeMode::Expanded) |
2812 | | Hir(_) | |
2813 | | HirTree | |
2814 | | ThirTree | |
9ffffee4 | 2815 | | ThirFlat |
6a06907d XL |
2816 | | Mir |
2817 | | MirCFG => true, | |
60c5eb7d XL |
2818 | } |
2819 | } | |
064997fb FG |
2820 | pub fn needs_hir(&self) -> bool { |
2821 | use PpMode::*; | |
2822 | match *self { | |
2823 | Source(_) | AstTree(_) => false, | |
2824 | ||
9ffffee4 | 2825 | Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true, |
064997fb FG |
2826 | } |
2827 | } | |
60c5eb7d XL |
2828 | |
2829 | pub fn needs_analysis(&self) -> bool { | |
2830 | use PpMode::*; | |
9ffffee4 | 2831 | matches!(*self, Mir | MirCFG | ThirTree | ThirFlat) |
60c5eb7d XL |
2832 | } |
2833 | } | |
2834 | ||
a1dfa0c6 | 2835 | /// Command-line arguments passed to the compiler have to be incorporated with |
5bcae85e SL |
2836 | /// the dependency tracking system for incremental compilation. This module |
2837 | /// provides some utilities to make this more convenient. | |
2838 | /// | |
a1dfa0c6 | 2839 | /// The values of all command-line arguments that are relevant for dependency |
5bcae85e SL |
2840 | /// tracking are hashed into a single value that determines whether the |
2841 | /// incremental compilation cache can be re-used or not. This hashing is done | |
e1599b0c XL |
2842 | /// via the `DepTrackingHash` trait defined below, since the standard `Hash` |
2843 | /// implementation might not be suitable (e.g., arguments are stored in a `Vec`, | |
5bcae85e SL |
2844 | /// the hash of which is order dependent, but we might not want the order of |
2845 | /// arguments to make a difference for the hash). | |
2846 | /// | |
e1599b0c | 2847 | /// However, since the value provided by `Hash::hash` often *is* suitable, |
5bcae85e | 2848 | /// especially for primitive types, there is the |
e1599b0c XL |
2849 | /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the |
2850 | /// `Hash` implementation for `DepTrackingHash`. It's important though that | |
5bcae85e | 2851 | /// we have an opt-in scheme here, so one is hopefully forced to think about |
a1dfa0c6 | 2852 | /// how the hash should be calculated when adding a new command-line argument. |
923072b8 | 2853 | pub(crate) mod dep_tracking { |
dfeec247 | 2854 | use super::{ |
5099ac24 | 2855 | BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType, |
9ffffee4 FG |
2856 | InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, |
2857 | OomStrategy, OptLevel, OutputType, OutputTypes, Passes, ResolveDocLinks, | |
2858 | SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, | |
2859 | TraitSolver, TrimmedDefPaths, | |
dfeec247 | 2860 | }; |
9fa01778 | 2861 | use crate::lint; |
5869c6ff | 2862 | use crate::options::WasiExecModel; |
17df50a5 | 2863 | use crate::utils::{NativeLib, NativeLibKind}; |
04454e1e | 2864 | use rustc_errors::LanguageIdentifier; |
dfeec247 XL |
2865 | use rustc_feature::UnstableFeatures; |
2866 | use rustc_span::edition::Edition; | |
94222f64 | 2867 | use rustc_span::RealFileName; |
f9f354fc | 2868 | use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel}; |
3c0e092e XL |
2869 | use rustc_target::spec::{ |
2870 | RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, | |
2871 | }; | |
dfeec247 | 2872 | use std::collections::hash_map::DefaultHasher; |
5bcae85e | 2873 | use std::collections::BTreeMap; |
9e0c209e | 2874 | use std::hash::Hash; |
6a06907d | 2875 | use std::num::NonZeroUsize; |
5bcae85e | 2876 | use std::path::PathBuf; |
5bcae85e SL |
2877 | |
2878 | pub trait DepTrackingHash { | |
136023e0 XL |
2879 | fn hash( |
2880 | &self, | |
2881 | hasher: &mut DefaultHasher, | |
2882 | error_format: ErrorOutputType, | |
2883 | for_crate_hash: bool, | |
2884 | ); | |
5bcae85e SL |
2885 | } |
2886 | ||
2887 | macro_rules! impl_dep_tracking_hash_via_hash { | |
17df50a5 | 2888 | ($($t:ty),+ $(,)?) => {$( |
5bcae85e | 2889 | impl DepTrackingHash for $t { |
136023e0 | 2890 | fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) { |
5bcae85e SL |
2891 | Hash::hash(self, hasher); |
2892 | } | |
2893 | } | |
17df50a5 | 2894 | )+}; |
5bcae85e SL |
2895 | } |
2896 | ||
17df50a5 | 2897 | impl<T: DepTrackingHash> DepTrackingHash for Option<T> { |
136023e0 XL |
2898 | fn hash( |
2899 | &self, | |
2900 | hasher: &mut DefaultHasher, | |
2901 | error_format: ErrorOutputType, | |
2902 | for_crate_hash: bool, | |
2903 | ) { | |
17df50a5 XL |
2904 | match self { |
2905 | Some(x) => { | |
2906 | Hash::hash(&1, hasher); | |
136023e0 | 2907 | DepTrackingHash::hash(x, hasher, error_format, for_crate_hash); |
5bcae85e | 2908 | } |
17df50a5 | 2909 | None => Hash::hash(&0, hasher), |
5bcae85e | 2910 | } |
17df50a5 | 2911 | } |
5bcae85e SL |
2912 | } |
2913 | ||
17df50a5 XL |
2914 | impl_dep_tracking_hash_via_hash!( |
2915 | bool, | |
2916 | usize, | |
2917 | NonZeroUsize, | |
2918 | u64, | |
2919 | String, | |
2920 | PathBuf, | |
2921 | lint::Level, | |
2922 | WasiExecModel, | |
2923 | u32, | |
2924 | RelocModel, | |
2925 | CodeModel, | |
2926 | TlsModel, | |
2927 | InstrumentCoverage, | |
9ffffee4 | 2928 | InstrumentXRay, |
17df50a5 XL |
2929 | CrateType, |
2930 | MergeFunctions, | |
2931 | PanicStrategy, | |
2932 | RelroLevel, | |
2933 | Passes, | |
2934 | OptLevel, | |
2935 | LtoCli, | |
2936 | DebugInfo, | |
2937 | UnstableFeatures, | |
17df50a5 XL |
2938 | NativeLib, |
2939 | NativeLibKind, | |
2940 | SanitizerSet, | |
2941 | CFGuard, | |
5099ac24 | 2942 | CFProtection, |
17df50a5 XL |
2943 | TargetTriple, |
2944 | Edition, | |
2945 | LinkerPluginLto, | |
9ffffee4 | 2946 | ResolveDocLinks, |
17df50a5 | 2947 | SplitDebuginfo, |
064997fb | 2948 | SplitDwarfKind, |
3c0e092e | 2949 | StackProtector, |
17df50a5 XL |
2950 | SwitchWithOptPath, |
2951 | SymbolManglingVersion, | |
2952 | SourceFileHashAlgorithm, | |
2953 | TrimmedDefPaths, | |
2954 | Option<LdImpl>, | |
136023e0 | 2955 | OutputType, |
94222f64 | 2956 | RealFileName, |
3c0e092e | 2957 | LocationDetail, |
5099ac24 | 2958 | BranchProtection, |
5e7ed085 | 2959 | OomStrategy, |
04454e1e | 2960 | LanguageIdentifier, |
9c376795 | 2961 | TraitSolver, |
17df50a5 | 2962 | ); |
5bcae85e SL |
2963 | |
2964 | impl<T1, T2> DepTrackingHash for (T1, T2) | |
0531ce1d XL |
2965 | where |
2966 | T1: DepTrackingHash, | |
2967 | T2: DepTrackingHash, | |
5bcae85e | 2968 | { |
136023e0 XL |
2969 | fn hash( |
2970 | &self, | |
2971 | hasher: &mut DefaultHasher, | |
2972 | error_format: ErrorOutputType, | |
2973 | for_crate_hash: bool, | |
2974 | ) { | |
5bcae85e | 2975 | Hash::hash(&0, hasher); |
136023e0 | 2976 | DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash); |
5bcae85e | 2977 | Hash::hash(&1, hasher); |
136023e0 | 2978 | DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash); |
5bcae85e SL |
2979 | } |
2980 | } | |
2981 | ||
476ff2be | 2982 | impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3) |
0531ce1d XL |
2983 | where |
2984 | T1: DepTrackingHash, | |
2985 | T2: DepTrackingHash, | |
2986 | T3: DepTrackingHash, | |
476ff2be | 2987 | { |
136023e0 XL |
2988 | fn hash( |
2989 | &self, | |
2990 | hasher: &mut DefaultHasher, | |
2991 | error_format: ErrorOutputType, | |
2992 | for_crate_hash: bool, | |
2993 | ) { | |
476ff2be | 2994 | Hash::hash(&0, hasher); |
136023e0 | 2995 | DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash); |
476ff2be | 2996 | Hash::hash(&1, hasher); |
136023e0 | 2997 | DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash); |
476ff2be | 2998 | Hash::hash(&2, hasher); |
136023e0 | 2999 | DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash); |
476ff2be SL |
3000 | } |
3001 | } | |
3002 | ||
17df50a5 | 3003 | impl<T: DepTrackingHash> DepTrackingHash for Vec<T> { |
136023e0 XL |
3004 | fn hash( |
3005 | &self, | |
3006 | hasher: &mut DefaultHasher, | |
3007 | error_format: ErrorOutputType, | |
3008 | for_crate_hash: bool, | |
3009 | ) { | |
17df50a5 XL |
3010 | Hash::hash(&self.len(), hasher); |
3011 | for (index, elem) in self.iter().enumerate() { | |
3012 | Hash::hash(&index, hasher); | |
136023e0 XL |
3013 | DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash); |
3014 | } | |
3015 | } | |
3016 | } | |
3017 | ||
3018 | impl DepTrackingHash for OutputTypes { | |
3019 | fn hash( | |
3020 | &self, | |
3021 | hasher: &mut DefaultHasher, | |
3022 | error_format: ErrorOutputType, | |
3023 | for_crate_hash: bool, | |
3024 | ) { | |
3025 | Hash::hash(&self.0.len(), hasher); | |
3026 | for (key, val) in &self.0 { | |
3027 | DepTrackingHash::hash(key, hasher, error_format, for_crate_hash); | |
3028 | if !for_crate_hash { | |
3029 | DepTrackingHash::hash(val, hasher, error_format, for_crate_hash); | |
3030 | } | |
17df50a5 XL |
3031 | } |
3032 | } | |
3033 | } | |
3034 | ||
5bcae85e | 3035 | // This is a stable hash because BTreeMap is a sorted container |
923072b8 | 3036 | pub(crate) fn stable_hash( |
0531ce1d XL |
3037 | sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, |
3038 | hasher: &mut DefaultHasher, | |
3039 | error_format: ErrorOutputType, | |
136023e0 | 3040 | for_crate_hash: bool, |
0531ce1d | 3041 | ) { |
5bcae85e SL |
3042 | for (key, sub_hash) in sub_hashes { |
3043 | // Using Hash::hash() instead of DepTrackingHash::hash() is fine for | |
3044 | // the keys, as they are just plain strings | |
3045 | Hash::hash(&key.len(), hasher); | |
3046 | Hash::hash(key, hasher); | |
136023e0 | 3047 | sub_hash.hash(hasher, error_format, for_crate_hash); |
5bcae85e SL |
3048 | } |
3049 | } | |
3050 | } | |
5e7ed085 FG |
3051 | |
3052 | /// Default behavior to use in out-of-memory situations. | |
3053 | #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)] | |
3054 | pub enum OomStrategy { | |
3055 | /// Generate a panic that can be caught by `catch_unwind`. | |
3056 | Panic, | |
3057 | ||
3058 | /// Abort the process immediately. | |
3059 | Abort, | |
3060 | } | |
3061 | ||
3062 | impl OomStrategy { | |
3063 | pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic"; | |
3064 | ||
3065 | pub fn should_panic(self) -> u8 { | |
3066 | match self { | |
3067 | OomStrategy::Panic => 1, | |
3068 | OomStrategy::Abort => 0, | |
3069 | } | |
3070 | } | |
3071 | } | |
064997fb FG |
3072 | |
3073 | /// How to run proc-macro code when building this crate | |
3074 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
3075 | pub enum ProcMacroExecutionStrategy { | |
3076 | /// Run the proc-macro code on the same thread as the server. | |
3077 | SameThread, | |
3078 | ||
3079 | /// Run the proc-macro code on a different thread. | |
3080 | CrossThread, | |
3081 | } | |
9c376795 FG |
3082 | |
3083 | /// Which format to use for `-Z dump-mono-stats` | |
3084 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
3085 | pub enum DumpMonoStatsFormat { | |
3086 | /// Pretty-print a markdown table | |
3087 | Markdown, | |
3088 | /// Emit structured JSON | |
3089 | Json, | |
3090 | } | |
3091 | ||
3092 | impl DumpMonoStatsFormat { | |
3093 | pub fn extension(self) -> &'static str { | |
3094 | match self { | |
3095 | Self::Markdown => "md", | |
3096 | Self::Json => "json", | |
3097 | } | |
3098 | } | |
3099 | } |