1use std::fmt;
4use std::sync::LazyLock;
5
6use rustc_data_structures::fx::FxHashSet;
7
8use crate::EarlyDiagCtxt;
9use crate::config::{
10 CodegenOptions, OutFileName, UnstableOptions, nightly_options, split_out_file_name,
11};
12use crate::macros::AllVariants;
13
14#[derive(#[automatically_derived]
impl ::core::clone::Clone for PrintRequest {
#[inline]
fn clone(&self) -> PrintRequest {
PrintRequest {
kind: ::core::clone::Clone::clone(&self.kind),
out: ::core::clone::Clone::clone(&self.out),
arg: ::core::clone::Clone::clone(&self.arg),
}
}
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for PrintRequest { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PrintRequest {
#[inline]
fn eq(&self, other: &PrintRequest) -> bool {
self.kind == other.kind && self.out == other.out &&
self.arg == other.arg
}
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for PrintRequest {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f, "PrintRequest",
"kind", &self.kind, "out", &self.out, "arg", &&self.arg)
}
}Debug)]
15pub struct PrintRequest {
16 pub kind: PrintKind,
17 pub out: OutFileName,
18 pub arg: Option<String>,
19}
20
21#[derive(#[automatically_derived]
impl ::core::marker::Copy for PrintKind { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for PrintKind { }
#[automatically_derived]
impl ::core::clone::Clone for PrintKind {
#[inline]
fn clone(&self) -> PrintKind { *self }
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for PrintKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PrintKind {
#[inline]
fn eq(&self, other: &PrintKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for PrintKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for PrintKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
PrintKind::AllTargetSpecsJson => "AllTargetSpecsJson",
PrintKind::BackendHasMnemonic => "BackendHasMnemonic",
PrintKind::BackendHasZstd => "BackendHasZstd",
PrintKind::CallingConventions => "CallingConventions",
PrintKind::Cfg => "Cfg",
PrintKind::CheckCfg => "CheckCfg",
PrintKind::CodeModels => "CodeModels",
PrintKind::CrateName => "CrateName",
PrintKind::CrateRootLintLevels => "CrateRootLintLevels",
PrintKind::DeploymentTarget => "DeploymentTarget",
PrintKind::FileNames => "FileNames",
PrintKind::HostTuple => "HostTuple",
PrintKind::LinkArgs => "LinkArgs",
PrintKind::NativeStaticLibs => "NativeStaticLibs",
PrintKind::RelocationModels => "RelocationModels",
PrintKind::SplitDebuginfo => "SplitDebuginfo",
PrintKind::StackProtectorStrategies =>
"StackProtectorStrategies",
PrintKind::SupportedCrateTypes => "SupportedCrateTypes",
PrintKind::Sysroot => "Sysroot",
PrintKind::TargetCPUs => "TargetCPUs",
PrintKind::TargetFeatures => "TargetFeatures",
PrintKind::TargetLibdir => "TargetLibdir",
PrintKind::TargetList => "TargetList",
PrintKind::TargetSpecJson => "TargetSpecJson",
PrintKind::TargetSpecJsonSchema => "TargetSpecJsonSchema",
PrintKind::TlsModels => "TlsModels",
PrintKind::WasmProcMacroTuple => "WasmProcMacroTuple",
})
}
}Debug)]
22#[derive(impl crate::macros::AllVariants for PrintKind {
const ALL_VARIANTS: &[PrintKind] =
&[PrintKind::AllTargetSpecsJson, PrintKind::BackendHasMnemonic,
PrintKind::BackendHasZstd, PrintKind::CallingConventions,
PrintKind::Cfg, PrintKind::CheckCfg, PrintKind::CodeModels,
PrintKind::CrateName, PrintKind::CrateRootLintLevels,
PrintKind::DeploymentTarget, PrintKind::FileNames,
PrintKind::HostTuple, PrintKind::LinkArgs,
PrintKind::NativeStaticLibs, PrintKind::RelocationModels,
PrintKind::SplitDebuginfo,
PrintKind::StackProtectorStrategies,
PrintKind::SupportedCrateTypes, PrintKind::Sysroot,
PrintKind::TargetCPUs, PrintKind::TargetFeatures,
PrintKind::TargetLibdir, PrintKind::TargetList,
PrintKind::TargetSpecJson, PrintKind::TargetSpecJsonSchema,
PrintKind::TlsModels, PrintKind::WasmProcMacroTuple];
}AllVariants)]
23pub enum PrintKind {
24 AllTargetSpecsJson,
27
28 BackendHasMnemonic,
30
31 BackendHasZstd,
33
34 CallingConventions,
36
37 Cfg,
39
40 CheckCfg,
42
43 CodeModels,
45
46 CrateName,
48
49 CrateRootLintLevels,
51
52 DeploymentTarget,
54
55 FileNames,
57
58 HostTuple,
60
61 LinkArgs,
63
64 NativeStaticLibs,
66
67 RelocationModels,
69
70 SplitDebuginfo,
72
73 StackProtectorStrategies,
75
76 SupportedCrateTypes,
78
79 Sysroot,
81
82 TargetCPUs,
84
85 TargetFeatures,
87
88 TargetLibdir,
90
91 TargetList,
93
94 TargetSpecJson,
96
97 TargetSpecJsonSchema,
99
100 TlsModels,
102
103 WasmProcMacroTuple,
105 }
107
108#[derive(#[automatically_derived]
impl ::core::marker::Copy for PrintCategory { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for PrintCategory { }
#[automatically_derived]
impl ::core::clone::Clone for PrintCategory {
#[inline]
fn clone(&self) -> PrintCategory { *self }
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for PrintCategory { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PrintCategory {
#[inline]
fn eq(&self, other: &PrintCategory) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for PrintCategory {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for PrintCategory {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
PrintCategory::Target => "Target",
PrintCategory::Codegen => "Codegen",
PrintCategory::Linker => "Linker",
PrintCategory::Crate => "Crate",
})
}
}Debug)]
109#[derive(impl crate::macros::AllVariants for PrintCategory {
const ALL_VARIANTS: &[PrintCategory] =
&[PrintCategory::Target, PrintCategory::Codegen,
PrintCategory::Linker, PrintCategory::Crate];
}AllVariants)]
110pub enum PrintCategory {
111 Target,
112 Codegen,
113 Linker,
114 Crate,
115}
116
117impl PrintKind {
118 fn name(self) -> &'static str {
119 use PrintKind::*;
120 match self {
121 AllTargetSpecsJson => "all-target-specs-json",
123 BackendHasMnemonic => "backend-has-mnemonic",
124 BackendHasZstd => "backend-has-zstd",
125 CallingConventions => "calling-conventions",
126 Cfg => "cfg",
127 CheckCfg => "check-cfg",
128 CodeModels => "code-models",
129 CrateName => "crate-name",
130 CrateRootLintLevels => "crate-root-lint-levels",
131 DeploymentTarget => "deployment-target",
132 FileNames => "file-names",
133 HostTuple => "host-tuple",
134 LinkArgs => "link-args",
135 NativeStaticLibs => "native-static-libs",
136 RelocationModels => "relocation-models",
137 SplitDebuginfo => "split-debuginfo",
138 StackProtectorStrategies => "stack-protector-strategies",
139 SupportedCrateTypes => "supported-crate-types",
140 Sysroot => "sysroot",
141 TargetCPUs => "target-cpus",
142 TargetFeatures => "target-features",
143 TargetLibdir => "target-libdir",
144 TargetList => "target-list",
145 TargetSpecJson => "target-spec-json",
146 TargetSpecJsonSchema => "target-spec-json-schema",
147 TlsModels => "tls-models",
148 WasmProcMacroTuple => "wasm-proc-macro-tuple",
149 }
151 }
152
153 fn category(self) -> PrintCategory {
154 use PrintKind::*;
155 match self {
156 TargetList | TargetSpecJsonSchema | AllTargetSpecsJson | TargetSpecJson
157 | TargetCPUs | TargetFeatures | DeploymentTarget | HostTuple | SupportedCrateTypes
158 | Sysroot | TargetLibdir | Cfg | CheckCfg | WasmProcMacroTuple => PrintCategory::Target,
159
160 BackendHasMnemonic
161 | BackendHasZstd
162 | CallingConventions
163 | CodeModels
164 | SplitDebuginfo
165 | StackProtectorStrategies
166 | TlsModels
167 | RelocationModels => PrintCategory::Codegen,
168
169 LinkArgs | NativeStaticLibs => PrintCategory::Linker,
170
171 CrateName | CrateRootLintLevels | FileNames => PrintCategory::Crate,
172 }
173 }
174
175 fn is_stable(self) -> bool {
176 use PrintKind::*;
177 match self {
178 CallingConventions
180 | Cfg
181 | CodeModels
182 | CrateName
183 | DeploymentTarget
184 | FileNames
185 | HostTuple
186 | LinkArgs
187 | NativeStaticLibs
188 | RelocationModels
189 | SplitDebuginfo
190 | StackProtectorStrategies
191 | Sysroot
192 | TargetCPUs
193 | TargetFeatures
194 | TargetLibdir
195 | TargetList
196 | TlsModels => true,
197
198 AllTargetSpecsJson => false,
200 BackendHasMnemonic => false, BackendHasZstd => false, CheckCfg => false,
203 CrateRootLintLevels => false,
204 SupportedCrateTypes => false,
205 TargetSpecJson => false,
206 TargetSpecJsonSchema => false,
207 WasmProcMacroTuple => false,
208 }
209 }
210
211 fn from_str(s: &str) -> Option<Self> {
212 Self::ALL_VARIANTS.iter().find(|kind| kind.name() == s).copied()
213 }
214}
215
216impl fmt::Display for PrintKind {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 self.name().fmt(f)
219 }
220}
221
222pub(crate) static PRINT_HELP: LazyLock<String> = LazyLock::new(|| {
223 let print_kinds =
224 PrintKind::ALL_VARIANTS.iter().map(|kind| kind.name()).collect::<Vec<_>>().join("|");
225 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Compiler information to print on stdout (or to a file)\nINFO may be one of <{0}>.",
print_kinds))
})format!(
226 "Compiler information to print on stdout (or to a file)\n\
227 INFO may be one of <{print_kinds}>.",
228 )
229});
230
231pub fn collect_print_requests(
232 early_dcx: &EarlyDiagCtxt,
233 cg: &mut CodegenOptions,
234 unstable_opts: &UnstableOptions,
235 matches: &getopts::Matches,
236 allowed: &[PrintCategory],
237) -> Vec<PrintRequest> {
238 let mut prints = Vec::<PrintRequest>::new();
239 if cg.target_cpu.as_deref() == Some("help") {
240 prints.push(PrintRequest {
241 kind: PrintKind::TargetCPUs,
242 out: OutFileName::Stdout,
243 arg: None,
244 });
245 cg.target_cpu = None;
246 };
247 if cg.target_feature == "help" {
248 prints.push(PrintRequest {
249 kind: PrintKind::TargetFeatures,
250 out: OutFileName::Stdout,
251 arg: None,
252 });
253 cg.target_feature = String::new();
254 }
255
256 let mut printed_paths = FxHashSet::default();
261
262 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
263 let (req, out) = split_out_file_name(&req);
264
265 let (kind, arg) = if let Some(mnemonic) = req.strip_prefix("backend-has-mnemonic") {
266 check_print_request_stability(early_dcx, unstable_opts, PrintKind::BackendHasMnemonic);
267 if let Some(mnemonic) = mnemonic.strip_prefix(':')
269 && !mnemonic.is_empty()
270 {
271 (PrintKind::BackendHasMnemonic, Some(mnemonic.to_string()))
272 } else {
273 early_dcx.early_fatal(
274 "expected mnemonic name after `--print=backend-has-mnemonic:`, \
275 for example: `--print=backend-has-mnemonic:RET`",
276 );
277 }
278 } else if let Some(print_kind) = PrintKind::from_str(req)
279 && allowed.contains(&print_kind.category())
280 {
281 check_print_request_stability(early_dcx, unstable_opts, print_kind);
282 (print_kind, None)
283 } else {
284 let is_nightly = nightly_options::match_is_nightly_build(matches);
285 emit_unknown_print_request_help(early_dcx, req, is_nightly, allowed)
286 };
287
288 let out = out.unwrap_or(OutFileName::Stdout);
289 if let OutFileName::Real(path) = &out {
290 if !printed_paths.insert(path.clone()) {
291 early_dcx.early_fatal(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot print multiple outputs to the same path: {0}",
path.display()))
})format!(
292 "cannot print multiple outputs to the same path: {}",
293 path.display(),
294 ));
295 }
296 }
297
298 PrintRequest { kind, out, arg }
299 }));
300
301 prints
302}
303
304fn check_print_request_stability(
305 early_dcx: &EarlyDiagCtxt,
306 unstable_opts: &UnstableOptions,
307 print_kind: PrintKind,
308) {
309 if !print_kind.is_stable() && !unstable_opts.unstable_options {
310 early_dcx.early_fatal(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the `-Z unstable-options` flag must also be passed to enable the `{0}` print option",
print_kind))
})format!(
311 "the `-Z unstable-options` flag must also be passed to enable the `{print_kind}` print option"
312 ));
313 }
314}
315
316fn emit_unknown_print_request_help(
317 early_dcx: &EarlyDiagCtxt,
318 req: &str,
319 is_nightly: bool,
320 allowed: &[PrintCategory],
321) -> ! {
322 let prints = PrintKind::ALL_VARIANTS
323 .iter()
324 .filter(|kind| is_nightly || kind.is_stable())
326 .filter(|kind| allowed.contains(&kind.category()))
327 .map(|kind| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", kind))
})format!("`{kind}`"))
328 .collect::<Vec<_>>()
329 .join(", ");
330
331 let mut diag = early_dcx.early_struct_fatal(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unknown print request: `{0}`",
req))
})format!("unknown print request: `{req}`"));
332 diag.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("valid print requests are: {0}",
prints))
})format!("valid print requests are: {prints}"));
333
334 if req == "lints" {
335 diag.help("use `-Whelp` to print a list of lints");
336 }
337
338 if allowed == PrintCategory::ALL_VARIANTS {
339 diag.help("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information");
340 }
341
342 diag.emit()
343}