Skip to main content

rustc_session/config/
print_request.rs

1//! Code for dealing with `--print` requests.
2
3use 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    // tidy-alphabetical-start
25    /// All target JSON specifications.
26    AllTargetSpecsJson,
27
28    /// Does the backend supports the [`PrintRequest::arg`] `asm!()` mnemonic? (perma-unstable)
29    BackendHasMnemonic,
30
31    /// Does the backend supports Zstd compression? (perma-unstable)
32    BackendHasZstd,
33
34    /// List of all calling conventions supported by rustc.
35    CallingConventions,
36
37    /// List of cfg values.
38    Cfg,
39
40    /// List of check-cfg values.
41    CheckCfg,
42
43    /// List of available code models for the current backend.
44    CodeModels,
45
46    /// Name of the crate being compiled.
47    CrateName,
48
49    /// Lint levels of the crate's root module.
50    CrateRootLintLevels,
51
52    /// The current selected deployment target. (Apple only)
53    DeploymentTarget,
54
55    /// The names of the files created by the `--emit=link` option. (e.g. `libfoo.a`)
56    FileNames,
57
58    /// Target-tuple of the host compiler.
59    HostTuple,
60
61    /// Linker invocations.
62    LinkArgs,
63
64    /// When compiling a `staticlib` crate, print the linker flags used.
65    NativeStaticLibs,
66
67    /// List of available relocation models for the current backend.
68    RelocationModels,
69
70    /// List of available split debuginfos for the current target.
71    SplitDebuginfo,
72
73    /// List of available stack protector strategies for the current backend.
74    StackProtectorStrategies,
75
76    /// List of available crate types for the current target.
77    SupportedCrateTypes,
78
79    /// Path to the sysroot.
80    Sysroot,
81
82    /// List of available CPU values for the current target.
83    TargetCPUs,
84
85    /// List of available target features for the current target.
86    TargetFeatures,
87
88    /// Path to the target libdir.
89    TargetLibdir,
90
91    /// List of supported targets.
92    TargetList,
93
94    /// Current target JSON specification.
95    TargetSpecJson,
96
97    /// Target JSON specification schema.
98    TargetSpecJsonSchema,
99
100    /// List of available TLS models for the current backend.
101    TlsModels,
102
103    /// Target-tuple for WebAssembly's proc-macro crates.
104    WasmProcMacroTuple,
105    // tidy-alphabetical-end
106}
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            // tidy-alphabetical-start
122            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            // tidy-alphabetical-end
150        }
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            // Stable values:
179            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            // Unstable values:
199            AllTargetSpecsJson => false,
200            BackendHasMnemonic => false, // (perma-unstable, for use by compiletest)
201            BackendHasZstd => false,     // (perma-unstable, for use by compiletest)
202            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    // We disallow reusing the same path in multiple prints, such as `--print
257    // cfg=output.txt --print link-args=output.txt`, because outputs are printed
258    // by disparate pieces of the compiler, and keeping track of which files
259    // need to be overwritten vs appended to is annoying.
260    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            // BackendHasMnemonic requires a mnemonic argument
268            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        // If we're not on nightly, we don't want to print unstable options
325        .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}