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),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for PrintRequest {
    #[inline]
    fn eq(&self, other: &PrintRequest) -> bool {
        self.kind == other.kind && self.out == other.out
    }
}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_field2_finish(f, "PrintRequest",
            "kind", &self.kind, "out", &&self.out)
    }
}Debug)]
15pub struct PrintRequest {
16    pub kind: PrintKind,
17    pub out: OutFileName,
18}
19
20#[derive(#[automatically_derived]
impl ::core::marker::Copy for PrintKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for PrintKind {
    #[inline]
    fn clone(&self) -> PrintKind { *self }
}Clone, #[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::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",
            })
    }
}Debug)]
21#[derive(impl crate::macros::AllVariants for PrintKind {
    const ALL_VARIANTS: &[PrintKind] =
        &[PrintKind::AllTargetSpecsJson, 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];
}AllVariants)]
22pub enum PrintKind {
23    // tidy-alphabetical-start
24    AllTargetSpecsJson,
25    BackendHasZstd,
26    CallingConventions,
27    Cfg,
28    CheckCfg,
29    CodeModels,
30    CrateName,
31    CrateRootLintLevels,
32    DeploymentTarget,
33    FileNames,
34    HostTuple,
35    LinkArgs,
36    NativeStaticLibs,
37    RelocationModels,
38    SplitDebuginfo,
39    StackProtectorStrategies,
40    SupportedCrateTypes,
41    Sysroot,
42    TargetCPUs,
43    TargetFeatures,
44    TargetLibdir,
45    TargetList,
46    TargetSpecJson,
47    TargetSpecJsonSchema,
48    TlsModels,
49    // tidy-alphabetical-end
50}
51
52impl PrintKind {
53    fn name(self) -> &'static str {
54        use PrintKind::*;
55        match self {
56            // tidy-alphabetical-start
57            AllTargetSpecsJson => "all-target-specs-json",
58            BackendHasZstd => "backend-has-zstd",
59            CallingConventions => "calling-conventions",
60            Cfg => "cfg",
61            CheckCfg => "check-cfg",
62            CodeModels => "code-models",
63            CrateName => "crate-name",
64            CrateRootLintLevels => "crate-root-lint-levels",
65            DeploymentTarget => "deployment-target",
66            FileNames => "file-names",
67            HostTuple => "host-tuple",
68            LinkArgs => "link-args",
69            NativeStaticLibs => "native-static-libs",
70            RelocationModels => "relocation-models",
71            SplitDebuginfo => "split-debuginfo",
72            StackProtectorStrategies => "stack-protector-strategies",
73            SupportedCrateTypes => "supported-crate-types",
74            Sysroot => "sysroot",
75            TargetCPUs => "target-cpus",
76            TargetFeatures => "target-features",
77            TargetLibdir => "target-libdir",
78            TargetList => "target-list",
79            TargetSpecJson => "target-spec-json",
80            TargetSpecJsonSchema => "target-spec-json-schema",
81            TlsModels => "tls-models",
82            // tidy-alphabetical-end
83        }
84    }
85
86    fn is_stable(self) -> bool {
87        use PrintKind::*;
88        match self {
89            // Stable values:
90            CallingConventions
91            | Cfg
92            | CodeModels
93            | CrateName
94            | DeploymentTarget
95            | FileNames
96            | HostTuple
97            | LinkArgs
98            | NativeStaticLibs
99            | RelocationModels
100            | SplitDebuginfo
101            | StackProtectorStrategies
102            | Sysroot
103            | TargetCPUs
104            | TargetFeatures
105            | TargetLibdir
106            | TargetList
107            | TlsModels => true,
108
109            // Unstable values:
110            AllTargetSpecsJson => false,
111            BackendHasZstd => false, // (perma-unstable, for use by compiletest)
112            CheckCfg => false,
113            CrateRootLintLevels => false,
114            SupportedCrateTypes => false,
115            TargetSpecJson => false,
116            TargetSpecJsonSchema => false,
117        }
118    }
119
120    fn from_str(s: &str) -> Option<Self> {
121        Self::ALL_VARIANTS.iter().find(|kind| kind.name() == s).copied()
122    }
123}
124
125impl fmt::Display for PrintKind {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        self.name().fmt(f)
128    }
129}
130
131pub(crate) static PRINT_HELP: LazyLock<String> = LazyLock::new(|| {
132    let print_kinds =
133        PrintKind::ALL_VARIANTS.iter().map(|kind| kind.name()).collect::<Vec<_>>().join("|");
134    ::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!(
135        "Compiler information to print on stdout (or to a file)\n\
136        INFO may be one of <{print_kinds}>.",
137    )
138});
139
140pub(crate) fn collect_print_requests(
141    early_dcx: &EarlyDiagCtxt,
142    cg: &mut CodegenOptions,
143    unstable_opts: &UnstableOptions,
144    matches: &getopts::Matches,
145) -> Vec<PrintRequest> {
146    let mut prints = Vec::<PrintRequest>::new();
147    if cg.target_cpu.as_deref() == Some("help") {
148        prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout });
149        cg.target_cpu = None;
150    };
151    if cg.target_feature == "help" {
152        prints.push(PrintRequest { kind: PrintKind::TargetFeatures, out: OutFileName::Stdout });
153        cg.target_feature = String::new();
154    }
155
156    // We disallow reusing the same path in multiple prints, such as `--print
157    // cfg=output.txt --print link-args=output.txt`, because outputs are printed
158    // by disparate pieces of the compiler, and keeping track of which files
159    // need to be overwritten vs appended to is annoying.
160    let mut printed_paths = FxHashSet::default();
161
162    prints.extend(matches.opt_strs("print").into_iter().map(|req| {
163        let (req, out) = split_out_file_name(&req);
164
165        let kind = if let Some(print_kind) = PrintKind::from_str(req) {
166            check_print_request_stability(early_dcx, unstable_opts, print_kind);
167            print_kind
168        } else {
169            let is_nightly = nightly_options::match_is_nightly_build(matches);
170            emit_unknown_print_request_help(early_dcx, req, is_nightly)
171        };
172
173        let out = out.unwrap_or(OutFileName::Stdout);
174        if let OutFileName::Real(path) = &out {
175            if !printed_paths.insert(path.clone()) {
176                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!(
177                    "cannot print multiple outputs to the same path: {}",
178                    path.display(),
179                ));
180            }
181        }
182
183        PrintRequest { kind, out }
184    }));
185
186    prints
187}
188
189fn check_print_request_stability(
190    early_dcx: &EarlyDiagCtxt,
191    unstable_opts: &UnstableOptions,
192    print_kind: PrintKind,
193) {
194    if !print_kind.is_stable() && !unstable_opts.unstable_options {
195        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!(
196            "the `-Z unstable-options` flag must also be passed to enable the `{print_kind}` print option"
197        ));
198    }
199}
200
201fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str, is_nightly: bool) -> ! {
202    let prints = PrintKind::ALL_VARIANTS
203        .iter()
204        // If we're not on nightly, we don't want to print unstable options
205        .filter(|kind| is_nightly || kind.is_stable())
206        .map(|kind| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}`", kind))
    })format!("`{kind}`"))
207        .collect::<Vec<_>>()
208        .join(", ");
209
210    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}`"));
211    diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("valid print requests are: {0}",
                prints))
    })format!("valid print requests are: {prints}"));
212
213    if req == "lints" {
214        diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("use `-Whelp` to print a list of lints"))
    })format!("use `-Whelp` to print a list of lints"));
215    }
216
217    diag.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information"))
    })format!("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information"));
218    diag.emit()
219}