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