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