Skip to main content

rustc_target/spec/
consistency.rs

1use core::result::Result;
2
3use rustc_abi::Endian;
4use rustc_data_structures::fx::FxHashSet;
5
6use crate::spec::{
7    Arch, Cc, CfgAbi, Env, FloatAbi, LinkerFlavor, Lld, LlvmAbi, Os, RelocModel, RustcAbi, Target,
8    TargetKind,
9};
10
11impl Target {
12    /// Check some basic consistency of the current target. For JSON targets we are less strict;
13    /// some of these checks are more guidelines than strict rules.
14    pub(super) fn check_consistency(&self, kind: TargetKind) -> Result<(), String> {
15        macro_rules! check {
16            ($b:expr, $($msg:tt)*) => {
17                if !$b {
18                    return Err(format!($($msg)*));
19                }
20            }
21        }
22        macro_rules! check_eq {
23            ($left:expr, $right:expr, $($msg:tt)*) => {
24                if ($left) != ($right) {
25                    return Err(format!($($msg)*));
26                }
27            }
28        }
29        macro_rules! check_ne {
30            ($left:expr, $right:expr, $($msg:tt)*) => {
31                if ($left) == ($right) {
32                    return Err(format!($($msg)*));
33                }
34            }
35        }
36        macro_rules! check_matches {
37            ($left:expr, $right:pat, $($msg:tt)*) => {
38                if !matches!($left, $right) {
39                    return Err(format!($($msg)*));
40                }
41            }
42        }
43
44        if (self.is_like_darwin) != (self.vendor == "apple") {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`is_like_darwin` must be set if and only if `vendor` is `apple`"))
                }));
};check_eq!(
45            self.is_like_darwin,
46            self.vendor == "apple",
47            "`is_like_darwin` must be set if and only if `vendor` is `apple`"
48        );
49        if (self.is_like_solaris) !=
        (#[allow(non_exhaustive_omitted_patterns)] match self.os {
                Os::Solaris | Os::Illumos => true,
                _ => false,
            }) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`is_like_solaris` must be set if and only if `os` is `solaris` or `illumos`"))
                }));
};check_eq!(
50            self.is_like_solaris,
51            matches!(self.os, Os::Solaris | Os::Illumos),
52            "`is_like_solaris` must be set if and only if `os` is `solaris` or `illumos`"
53        );
54        if (self.is_like_gpu) !=
        (self.arch == Arch::Nvptx64 || self.arch == Arch::AmdGpu) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`is_like_gpu` must be set if and only if `target` is `nvptx64` or `amdgcn`"))
                }));
};check_eq!(
55            self.is_like_gpu,
56            self.arch == Arch::Nvptx64 || self.arch == Arch::AmdGpu,
57            "`is_like_gpu` must be set if and only if `target` is `nvptx64` or `amdgcn`"
58        );
59        if (self.is_like_windows) !=
        (#[allow(non_exhaustive_omitted_patterns)] match self.os {
                Os::Windows | Os::Uefi | Os::Cygwin => true,
                _ => false,
            }) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`is_like_windows` must be set if and only if `os` is `windows`, `uefi` or `cygwin`"))
                }));
};check_eq!(
60            self.is_like_windows,
61            matches!(self.os, Os::Windows | Os::Uefi | Os::Cygwin),
62            "`is_like_windows` must be set if and only if `os` is `windows`, `uefi` or `cygwin`"
63        );
64        if (self.is_like_wasm) !=
        (#[allow(non_exhaustive_omitted_patterns)] match self.arch {
                Arch::Wasm32 | Arch::Wasm64 => true,
                _ => false,
            }) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`is_like_wasm` must be set if and only if `arch` is `wasm32` or `wasm64`"))
                }));
};check_eq!(
65            self.is_like_wasm,
66            matches!(self.arch, Arch::Wasm32 | Arch::Wasm64),
67            "`is_like_wasm` must be set if and only if `arch` is `wasm32` or `wasm64`"
68        );
69        if self.is_like_msvc {
70            if !self.is_like_windows {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("if `is_like_msvc` is set, `is_like_windows` must be set"))
                }));
};check!(self.is_like_windows, "if `is_like_msvc` is set, `is_like_windows` must be set");
71        }
72        if self.os == Os::Emscripten {
73            if !self.is_like_wasm {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("the `emcscripten` os only makes sense on wasm-like targets"))
                }));
};check!(self.is_like_wasm, "the `emcscripten` os only makes sense on wasm-like targets");
74        }
75
76        // Check that default linker flavor is compatible with some other key properties.
77        if (self.is_like_darwin) !=
        (#[allow(non_exhaustive_omitted_patterns)] match self.linker_flavor {
                LinkerFlavor::Darwin(..) => true,
                _ => false,
            }) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`linker_flavor` must be `darwin` if and only if `is_like_darwin` is set"))
                }));
};check_eq!(
78            self.is_like_darwin,
79            matches!(self.linker_flavor, LinkerFlavor::Darwin(..)),
80            "`linker_flavor` must be `darwin` if and only if `is_like_darwin` is set"
81        );
82        if (self.is_like_msvc) !=
        (#[allow(non_exhaustive_omitted_patterns)] match self.linker_flavor {
                LinkerFlavor::Msvc(..) => true,
                _ => false,
            }) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`linker_flavor` must be `msvc` if and only if `is_like_msvc` is set"))
                }));
};check_eq!(
83            self.is_like_msvc,
84            matches!(self.linker_flavor, LinkerFlavor::Msvc(..)),
85            "`linker_flavor` must be `msvc` if and only if `is_like_msvc` is set"
86        );
87        if (self.is_like_wasm && self.os != Os::Emscripten) !=
        (#[allow(non_exhaustive_omitted_patterns)] match self.linker_flavor {
                LinkerFlavor::WasmLld(..) => true,
                _ => false,
            }) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`linker_flavor` must be `wasm-lld` if and only if `is_like_wasm` is set and the `os` is not `emscripten`"))
                }));
};check_eq!(
88            self.is_like_wasm && self.os != Os::Emscripten,
89            matches!(self.linker_flavor, LinkerFlavor::WasmLld(..)),
90            "`linker_flavor` must be `wasm-lld` if and only if `is_like_wasm` is set and the `os` is not `emscripten`",
91        );
92        if (self.os == Os::Emscripten) !=
        (#[allow(non_exhaustive_omitted_patterns)] match self.linker_flavor {
                LinkerFlavor::EmCc => true,
                _ => false,
            }) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`linker_flavor` must be `em-cc` if and only if `os` is `emscripten`"))
                }));
};check_eq!(
93            self.os == Os::Emscripten,
94            matches!(self.linker_flavor, LinkerFlavor::EmCc),
95            "`linker_flavor` must be `em-cc` if and only if `os` is `emscripten`"
96        );
97        if (self.arch == Arch::Bpf) !=
        (#[allow(non_exhaustive_omitted_patterns)] match self.linker_flavor {
                LinkerFlavor::Bpf => true,
                _ => false,
            }) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`linker_flavor` must be `bpf` if and only if `arch` is `bpf`"))
                }));
};check_eq!(
98            self.arch == Arch::Bpf,
99            matches!(self.linker_flavor, LinkerFlavor::Bpf),
100            "`linker_flavor` must be `bpf` if and only if `arch` is `bpf`"
101        );
102
103        for args in [
104            &self.pre_link_args,
105            &self.late_link_args,
106            &self.late_link_args_dynamic,
107            &self.late_link_args_static,
108            &self.post_link_args,
109        ] {
110            for (&flavor, flavor_args) in args {
111                if !(!flavor_args.is_empty() || self.arch == Arch::Avr) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("linker flavor args must not be empty"))
                }));
};check!(
112                    !flavor_args.is_empty() || self.arch == Arch::Avr,
113                    "linker flavor args must not be empty"
114                );
115                // Check that flavors mentioned in link args are compatible with the default flavor.
116                match self.linker_flavor {
117                    LinkerFlavor::Gnu(..) => {
118                        if !#[allow(non_exhaustive_omitted_patterns)] match flavor {
            LinkerFlavor::Gnu(..) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("mixing GNU and non-GNU linker flavors"))
                }));
};check_matches!(
119                            flavor,
120                            LinkerFlavor::Gnu(..),
121                            "mixing GNU and non-GNU linker flavors"
122                        );
123                    }
124                    LinkerFlavor::Darwin(..) => {
125                        if !#[allow(non_exhaustive_omitted_patterns)] match flavor {
            LinkerFlavor::Darwin(..) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("mixing Darwin and non-Darwin linker flavors"))
                }));
}check_matches!(
126                            flavor,
127                            LinkerFlavor::Darwin(..),
128                            "mixing Darwin and non-Darwin linker flavors"
129                        )
130                    }
131                    LinkerFlavor::WasmLld(..) => {
132                        if !#[allow(non_exhaustive_omitted_patterns)] match flavor {
            LinkerFlavor::WasmLld(..) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("mixing wasm and non-wasm linker flavors"))
                }));
}check_matches!(
133                            flavor,
134                            LinkerFlavor::WasmLld(..),
135                            "mixing wasm and non-wasm linker flavors"
136                        )
137                    }
138                    LinkerFlavor::Unix(..) => {
139                        if !#[allow(non_exhaustive_omitted_patterns)] match flavor {
            LinkerFlavor::Unix(..) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("mixing unix and non-unix linker flavors"))
                }));
};check_matches!(
140                            flavor,
141                            LinkerFlavor::Unix(..),
142                            "mixing unix and non-unix linker flavors"
143                        );
144                    }
145                    LinkerFlavor::Msvc(..) => {
146                        if !#[allow(non_exhaustive_omitted_patterns)] match flavor {
            LinkerFlavor::Msvc(..) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("mixing MSVC and non-MSVC linker flavors"))
                }));
};check_matches!(
147                            flavor,
148                            LinkerFlavor::Msvc(..),
149                            "mixing MSVC and non-MSVC linker flavors"
150                        );
151                    }
152                    LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Llbc => {
153                        if (flavor) != (self.linker_flavor) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("mixing different linker flavors"))
                }));
}check_eq!(flavor, self.linker_flavor, "mixing different linker flavors")
154                    }
155                }
156
157                // Check that link args for cc and non-cc versions of flavors are consistent.
158                let check_noncc = |noncc_flavor| -> Result<(), String> {
159                    if let Some(noncc_args) = args.get(&noncc_flavor) {
160                        for arg in flavor_args {
161                            if let Some(suffix) = arg.strip_prefix("-Wl,") {
162                                if !noncc_args.iter().any(|a| a == suffix) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!(" link args for cc and non-cc versions of flavors are not consistent"))
                }));
};check!(
163                                    noncc_args.iter().any(|a| a == suffix),
164                                    " link args for cc and non-cc versions of flavors are not consistent"
165                                );
166                            }
167                        }
168                    }
169                    Ok(())
170                };
171
172                match self.linker_flavor {
173                    LinkerFlavor::Gnu(Cc::Yes, lld) => check_noncc(LinkerFlavor::Gnu(Cc::No, lld))?,
174                    LinkerFlavor::WasmLld(Cc::Yes) => check_noncc(LinkerFlavor::WasmLld(Cc::No))?,
175                    LinkerFlavor::Unix(Cc::Yes) => check_noncc(LinkerFlavor::Unix(Cc::No))?,
176                    _ => {}
177                }
178            }
179
180            // Check that link args for lld and non-lld versions of flavors are consistent.
181            for cc in [Cc::No, Cc::Yes] {
182                if (args.get(&LinkerFlavor::Gnu(cc, Lld::No))) !=
        (args.get(&LinkerFlavor::Gnu(cc, Lld::Yes))) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("link args for lld and non-lld versions of flavors are not consistent"))
                }));
};check_eq!(
183                    args.get(&LinkerFlavor::Gnu(cc, Lld::No)),
184                    args.get(&LinkerFlavor::Gnu(cc, Lld::Yes)),
185                    "link args for lld and non-lld versions of flavors are not consistent",
186                );
187                if (args.get(&LinkerFlavor::Darwin(cc, Lld::No))) !=
        (args.get(&LinkerFlavor::Darwin(cc, Lld::Yes))) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("link args for lld and non-lld versions of flavors are not consistent"))
                }));
};check_eq!(
188                    args.get(&LinkerFlavor::Darwin(cc, Lld::No)),
189                    args.get(&LinkerFlavor::Darwin(cc, Lld::Yes)),
190                    "link args for lld and non-lld versions of flavors are not consistent",
191                );
192            }
193            if (args.get(&LinkerFlavor::Msvc(Lld::No))) !=
        (args.get(&LinkerFlavor::Msvc(Lld::Yes))) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("link args for lld and non-lld versions of flavors are not consistent"))
                }));
};check_eq!(
194                args.get(&LinkerFlavor::Msvc(Lld::No)),
195                args.get(&LinkerFlavor::Msvc(Lld::Yes)),
196                "link args for lld and non-lld versions of flavors are not consistent",
197            );
198        }
199
200        if self.link_self_contained.is_disabled() {
201            if !(self.pre_link_objects_self_contained.is_empty() &&
            self.post_link_objects_self_contained.is_empty()) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("if `link_self_contained` is disabled, then `pre_link_objects_self_contained` and `post_link_objects_self_contained` must be empty"))
                }));
};check!(
202                self.pre_link_objects_self_contained.is_empty()
203                    && self.post_link_objects_self_contained.is_empty(),
204                "if `link_self_contained` is disabled, then `pre_link_objects_self_contained` and `post_link_objects_self_contained` must be empty",
205            );
206        }
207
208        // If your target really needs to deviate from the rules below,
209        // except it and document the reasons.
210        // Keep the default "unknown" vendor instead.
211        if (self.vendor) == ("") {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`vendor` cannot be empty"))
                }));
};check_ne!(self.vendor, "", "`vendor` cannot be empty");
212        if let Os::Other(s) = &self.os {
213            if !!s.is_empty() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`os` cannot be empty"))
                }));
};check!(!s.is_empty(), "`os` cannot be empty");
214        }
215        if !self.can_use_os_unknown() {
216            // Keep the default "none" for bare metal targets instead.
217            if (self.os) == (Os::Unknown) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`unknown` os can only be used on particular targets; use `none` for bare-metal targets"))
                }));
};check_ne!(
218                self.os,
219                Os::Unknown,
220                "`unknown` os can only be used on particular targets; use `none` for bare-metal targets"
221            );
222        }
223
224        // Check dynamic linking stuff.
225        // We skip this for JSON targets since otherwise, our default values would fail this test.
226        // These checks are not critical for correctness, but more like default guidelines.
227        // FIXME (https://github.com/rust-lang/rust/issues/133459): do we want to change the JSON
228        // target defaults so that they pass these checks?
229        if kind == TargetKind::Builtin {
230            // BPF: when targeting user space vms (like rbpf), those can load dynamic libraries.
231            // hexagon: when targeting QuRT, that OS can load dynamic libraries.
232            // wasm{32,64}: dynamic linking is inherent in the definition of the VM.
233            if self.os == Os::None
234                && !#[allow(non_exhaustive_omitted_patterns)] match self.arch {
    Arch::Bpf | Arch::Hexagon | Arch::Wasm32 | Arch::Wasm64 => true,
    _ => false,
}matches!(self.arch, Arch::Bpf | Arch::Hexagon | Arch::Wasm32 | Arch::Wasm64)
235            {
236                if !!self.dynamic_linking {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("dynamic linking is not supported on this OS/architecture"))
                }));
};check!(
237                    !self.dynamic_linking,
238                    "dynamic linking is not supported on this OS/architecture"
239                );
240            }
241            if self.only_cdylib
242                || self.crt_static_allows_dylibs
243                || !self.late_link_args_dynamic.is_empty()
244            {
245                if !self.dynamic_linking {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("dynamic linking must be allowed when `only_cdylib` or `crt_static_allows_dylibs` or `late_link_args_dynamic` are set"))
                }));
};check!(
246                    self.dynamic_linking,
247                    "dynamic linking must be allowed when `only_cdylib` or `crt_static_allows_dylibs` or `late_link_args_dynamic` are set"
248                );
249            }
250            // Apparently PIC was slow on wasm at some point, see comments in wasm_base.rs
251            if self.dynamic_linking && !self.is_like_wasm {
252                if (self.relocation_model) != (RelocModel::Pic) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("targets that support dynamic linking must use the `pic` relocation model"))
                }));
};check_eq!(
253                    self.relocation_model,
254                    RelocModel::Pic,
255                    "targets that support dynamic linking must use the `pic` relocation model"
256                );
257            }
258            if self.position_independent_executables {
259                if (self.relocation_model) != (RelocModel::Pic) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("targets that support position-independent executables must use the `pic` relocation model"))
                }));
};check_eq!(
260                    self.relocation_model,
261                    RelocModel::Pic,
262                    "targets that support position-independent executables must use the `pic` relocation model"
263                );
264            }
265            // The UEFI targets do not support dynamic linking but still require PIC (#101377).
266            if self.relocation_model == RelocModel::Pic && self.os != Os::Uefi {
267                if !(self.dynamic_linking || self.position_independent_executables) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("when the relocation model is `pic`, the target must support dynamic linking or use position-independent executables. Set the relocation model to `static` to avoid this requirement"))
                }));
};check!(
268                    self.dynamic_linking || self.position_independent_executables,
269                    "when the relocation model is `pic`, the target must support dynamic linking or use position-independent executables. \
270                Set the relocation model to `static` to avoid this requirement"
271                );
272            }
273            if self.static_position_independent_executables {
274                if !self.position_independent_executables {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("if `static_position_independent_executables` is set, then `position_independent_executables` must be set"))
                }));
};check!(
275                    self.position_independent_executables,
276                    "if `static_position_independent_executables` is set, then `position_independent_executables` must be set"
277                );
278            }
279            if self.position_independent_executables {
280                if !self.executables {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("if `position_independent_executables` is set then `executables` must be set"))
                }));
};check!(
281                    self.executables,
282                    "if `position_independent_executables` is set then `executables` must be set"
283                );
284            }
285        }
286
287        // Check crt static stuff
288        if self.crt_static_default || self.crt_static_allows_dylibs {
289            if !self.crt_static_respected {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("static CRT can be enabled but `crt_static_respected` is not set"))
                }));
};check!(
290                self.crt_static_respected,
291                "static CRT can be enabled but `crt_static_respected` is not set"
292            );
293        }
294
295        // Ensure built-in targets don't use the `Other` variants.
296        if kind == TargetKind::Builtin {
297            if !!#[allow(non_exhaustive_omitted_patterns)] match self.arch {
                Arch::Other(_) => true,
                _ => false,
            } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`Arch::Other` is only meant for JSON targets"))
                }));
};check!(
298                !matches!(self.arch, Arch::Other(_)),
299                "`Arch::Other` is only meant for JSON targets"
300            );
301            if !!#[allow(non_exhaustive_omitted_patterns)] match self.os {
                Os::Other(_) => true,
                _ => false,
            } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`Os::Other` is only meant for JSON targets"))
                }));
};check!(!matches!(self.os, Os::Other(_)), "`Os::Other` is only meant for JSON targets");
302            if !!#[allow(non_exhaustive_omitted_patterns)] match self.env {
                Env::Other(_) => true,
                _ => false,
            } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`Env::Other` is only meant for JSON targets"))
                }));
};check!(
303                !matches!(self.env, Env::Other(_)),
304                "`Env::Other` is only meant for JSON targets"
305            );
306            if !!#[allow(non_exhaustive_omitted_patterns)] match self.cfg_abi {
                CfgAbi::Other(_) => true,
                _ => false,
            } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`CfgAbi::Other` is only meant for JSON targets"))
                }));
};check!(
307                !matches!(self.cfg_abi, CfgAbi::Other(_)),
308                "`CfgAbi::Other` is only meant for JSON targets"
309            );
310            if !!#[allow(non_exhaustive_omitted_patterns)] match self.llvm_abiname {
                LlvmAbi::Other(_) => true,
                _ => false,
            } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`LlvmAbi::Other` is only meant for JSON targets"))
                }));
};check!(
311                !matches!(self.llvm_abiname, LlvmAbi::Other(_)),
312                "`LlvmAbi::Other` is only meant for JSON targets"
313            );
314        }
315
316        // Check ABI flag consistency, for the architectures where we have proper ABI treatment.
317        // To ensure targets are trated consistently, please consult with the team before allowing
318        // new cases.
319        match self.arch {
320            Arch::X86 => {
321                if !(self.llvm_abiname == LlvmAbi::Unspecified) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_abiname` is unused on x86-32"))
                }));
};check!(
322                    self.llvm_abiname == LlvmAbi::Unspecified,
323                    "`llvm_abiname` is unused on x86-32"
324                );
325                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on x86-32"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on x86-32");
326                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.rustc_abi,
                &self.cfg_abi) {
            (Some(RustcAbi::Softfloat),
                CfgAbi::SoftFloat | CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (Some(RustcAbi::X86Sse2) | None,
                CfgAbi::Uwp | CfgAbi::Llvm | CfgAbi::Sim | CfgAbi::Unspecified
                | CfgAbi::Other(_)) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid x86-32 Rust-specific ABI and `cfg(target_abi)` combination:\nRust-specific ABI: {0:?}\ncfg(target_abi): {1}",
                            self.rustc_abi, self.cfg_abi))
                }));
};check_matches!(
327                    (&self.rustc_abi, &self.cfg_abi),
328                    // FIXME: we do not currently set a target_abi for softfloat targets here,
329                    // but we probably should, so we already allow it.
330                    (
331                        Some(RustcAbi::Softfloat),
332                        CfgAbi::SoftFloat | CfgAbi::Unspecified | CfgAbi::Other(_)
333                    ) | (
334                        Some(RustcAbi::X86Sse2) | None,
335                        CfgAbi::Uwp
336                            | CfgAbi::Llvm
337                            | CfgAbi::Sim
338                            | CfgAbi::Unspecified
339                            | CfgAbi::Other(_)
340                    ),
341                    "invalid x86-32 Rust-specific ABI and `cfg(target_abi)` combination:\n\
342                    Rust-specific ABI: {:?}\n\
343                    cfg(target_abi): {}",
344                    self.rustc_abi,
345                    self.cfg_abi,
346                );
347            }
348            Arch::X86_64 => {
349                if !(self.llvm_abiname == LlvmAbi::Unspecified) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_abiname` is unused on x86-64"))
                }));
};check!(
350                    self.llvm_abiname == LlvmAbi::Unspecified,
351                    "`llvm_abiname` is unused on x86-64"
352                );
353                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on x86-64"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on x86-64");
354                // FIXME: we do not currently set a target_abi for softfloat targets here, but we
355                // probably should, so we already allow it.
356                // FIXME: Ensure that target_abi = "x32" correlates with actually using that ABI.
357                // Do any of the others need a similar check?
358                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.rustc_abi,
                &self.cfg_abi) {
            (Some(RustcAbi::Softfloat),
                CfgAbi::SoftFloat | CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (None,
                CfgAbi::X32 | CfgAbi::Llvm | CfgAbi::Fortanix | CfgAbi::Uwp |
                CfgAbi::MacAbi | CfgAbi::Sim | CfgAbi::Unspecified |
                CfgAbi::Other(_)) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid x86-64 Rust-specific ABI and `cfg(target_abi)` combination:\nRust-specific ABI: {0:?}\ncfg(target_abi): {1}",
                            self.rustc_abi, self.cfg_abi))
                }));
};check_matches!(
359                    (&self.rustc_abi, &self.cfg_abi),
360                    (
361                        Some(RustcAbi::Softfloat),
362                        CfgAbi::SoftFloat | CfgAbi::Unspecified | CfgAbi::Other(_)
363                    ) | (
364                        None,
365                        CfgAbi::X32
366                            | CfgAbi::Llvm
367                            | CfgAbi::Fortanix
368                            | CfgAbi::Uwp
369                            | CfgAbi::MacAbi
370                            | CfgAbi::Sim
371                            | CfgAbi::Unspecified
372                            | CfgAbi::Other(_)
373                    ),
374                    "invalid x86-64 Rust-specific ABI and `cfg(target_abi)` combination:\n\
375                    Rust-specific ABI: {:?}\n\
376                    cfg(target_abi): {}",
377                    self.rustc_abi,
378                    self.cfg_abi,
379                );
380            }
381            Arch::RiscV32 => {
382                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on RISC-V"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on RISC-V");
383                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on RISC-V"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on RISC-V");
384                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::Ilp32, CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (LlvmAbi::Ilp32f, CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (LlvmAbi::Ilp32d, CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (LlvmAbi::Ilp32e, CfgAbi::Ilp32e) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid RISC-V ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
385                    (&self.llvm_abiname, &self.cfg_abi),
386                    (LlvmAbi::Ilp32, CfgAbi::Unspecified | CfgAbi::Other(_))
387                        | (LlvmAbi::Ilp32f, CfgAbi::Unspecified | CfgAbi::Other(_))
388                        | (LlvmAbi::Ilp32d, CfgAbi::Unspecified | CfgAbi::Other(_))
389                        | (LlvmAbi::Ilp32e, CfgAbi::Ilp32e),
390                    "invalid RISC-V ABI name and `cfg(target_abi)` combination:\n\
391                     ABI name: {}\n\
392                     cfg(target_abi): {}",
393                    self.llvm_abiname,
394                    self.cfg_abi,
395                );
396            }
397            Arch::RiscV64 => {
398                // Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI.
399                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on RISC-V"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on RISC-V");
400                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on RISC-V"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on RISC-V");
401                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::Lp64, CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (LlvmAbi::Lp64f, CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (LlvmAbi::Lp64d, CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (LlvmAbi::Lp64e, CfgAbi::Unspecified | CfgAbi::Other(_)) =>
                true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid RISC-V ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
402                    (&self.llvm_abiname, &self.cfg_abi),
403                    (LlvmAbi::Lp64, CfgAbi::Unspecified | CfgAbi::Other(_))
404                        | (LlvmAbi::Lp64f, CfgAbi::Unspecified | CfgAbi::Other(_))
405                        | (LlvmAbi::Lp64d, CfgAbi::Unspecified | CfgAbi::Other(_))
406                        | (LlvmAbi::Lp64e, CfgAbi::Unspecified | CfgAbi::Other(_)),
407                    "invalid RISC-V ABI name and `cfg(target_abi)` combination:\n\
408                     ABI name: {}\n\
409                     cfg(target_abi): {}",
410                    self.llvm_abiname,
411                    self.cfg_abi,
412                );
413            }
414            Arch::Arm => {
415                if !(self.llvm_abiname == LlvmAbi::Unspecified) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_abiname` is unused on ARM"))
                }));
};check!(
416                    self.llvm_abiname == LlvmAbi::Unspecified,
417                    "`llvm_abiname` is unused on ARM"
418                );
419                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on ARM"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on ARM");
420                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_floatabi,
                &self.cfg_abi) {
            (Some(FloatAbi::Hard),
                CfgAbi::EabiHf | CfgAbi::Uwp | CfgAbi::Unspecified |
                CfgAbi::Other(_)) | (Some(FloatAbi::Soft), CfgAbi::Eabi) =>
                true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("Invalid combination of float ABI and `cfg(target_abi)` for ARM target\nfloat ABI: {0:?}\ncfg(target_abi): {1}",
                            self.llvm_floatabi, self.cfg_abi))
                }));
}check_matches!(
421                    (&self.llvm_floatabi, &self.cfg_abi),
422                    (
423                        Some(FloatAbi::Hard),
424                        CfgAbi::EabiHf | CfgAbi::Uwp | CfgAbi::Unspecified | CfgAbi::Other(_)
425                    ) | (Some(FloatAbi::Soft), CfgAbi::Eabi),
426                    "Invalid combination of float ABI and `cfg(target_abi)` for ARM target\n\
427                     float ABI: {:?}\n\
428                     cfg(target_abi): {}",
429                    self.llvm_floatabi,
430                    self.cfg_abi,
431                )
432            }
433            Arch::AArch64 => {
434                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on aarch64"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on aarch64");
435                // FIXME: Ensure that target_abi = "ilp32" correlates with actually using that ABI.
436                // Do any of the others need a similar check?
437                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.rustc_abi, &self.cfg_abi) {
            (LlvmAbi::Pauthtest, None, CfgAbi::Pauthtest) |
                (LlvmAbi::Unspecified, Some(RustcAbi::Softfloat),
                CfgAbi::SoftFloat) |
                (LlvmAbi::Unspecified, None,
                CfgAbi::Ilp32 | CfgAbi::Llvm | CfgAbi::MacAbi | CfgAbi::Sim |
                CfgAbi::Uwp | CfgAbi::Unspecified | CfgAbi::Other(_)) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid aarch64 ABI combination:\nLLVM ABI: {0}\nRust-specific ABI: {1:?}\ncfg(target_abi): {2}",
                            self.llvm_abiname, self.rustc_abi, self.cfg_abi))
                }));
};check_matches!(
438                    (&self.llvm_abiname, &self.rustc_abi, &self.cfg_abi),
439                    (LlvmAbi::Pauthtest, None, CfgAbi::Pauthtest)
440                        | (LlvmAbi::Unspecified, Some(RustcAbi::Softfloat), CfgAbi::SoftFloat)
441                        | (
442                            LlvmAbi::Unspecified,
443                            None,
444                            CfgAbi::Ilp32
445                                | CfgAbi::Llvm
446                                | CfgAbi::MacAbi
447                                | CfgAbi::Sim
448                                | CfgAbi::Uwp
449                                | CfgAbi::Unspecified
450                                | CfgAbi::Other(_)
451                        ),
452                    "invalid aarch64 ABI combination:\n\
453                    LLVM ABI: {}\n\
454                    Rust-specific ABI: {:?}\n\
455                    cfg(target_abi): {}",
456                    self.llvm_abiname,
457                    self.rustc_abi,
458                    self.cfg_abi,
459                );
460            }
461            Arch::PowerPC => {
462                if !(self.llvm_abiname == LlvmAbi::Unspecified) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_abiname` is unused on PowerPC"))
                }));
};check!(
463                    self.llvm_abiname == LlvmAbi::Unspecified,
464                    "`llvm_abiname` is unused on PowerPC"
465                );
466                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on PowerPC"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on PowerPC");
467                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.rustc_abi,
                &self.cfg_abi) {
            (Some(RustcAbi::PowerPcSpe), CfgAbi::Spe) |
                (None, CfgAbi::Unspecified | CfgAbi::Other(_)) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid PowerPC Rust-specific ABI and `cfg(target_abi)` combination:\nRust-specific ABI: {0:?}\ncfg(target_abi): {1}",
                            self.rustc_abi, self.cfg_abi))
                }));
};check_matches!(
468                    (&self.rustc_abi, &self.cfg_abi),
469                    (Some(RustcAbi::PowerPcSpe), CfgAbi::Spe)
470                        | (None, CfgAbi::Unspecified | CfgAbi::Other(_)),
471                    "invalid PowerPC Rust-specific ABI and `cfg(target_abi)` combination:\n\
472                    Rust-specific ABI: {:?}\n\
473                    cfg(target_abi): {}",
474                    self.rustc_abi,
475                    self.cfg_abi,
476                );
477            }
478            Arch::PowerPC64 => {
479                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on PowerPC64"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on PowerPC64");
480                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on PowerPC64"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on PowerPC64");
481                // PowerPC64 targets that are not AIX must set their ABI to either ELFv1 or ELFv2
482                if self.os == Os::Aix {
483                    // FIXME: Check that `target_abi` matches the actually configured ABI
484                    // (vec-default vs vec-ext).
485                    if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::Unspecified, CfgAbi::VecDefault | CfgAbi::VecExtAbi) =>
                true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid PowerPC64 AIX ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
486                        (&self.llvm_abiname, &self.cfg_abi),
487                        (LlvmAbi::Unspecified, CfgAbi::VecDefault | CfgAbi::VecExtAbi),
488                        "invalid PowerPC64 AIX ABI name and `cfg(target_abi)` combination:\n\
489                        ABI name: {}\n\
490                        cfg(target_abi): {}",
491                        self.llvm_abiname,
492                        self.cfg_abi,
493                    );
494                } else if self.endian == Endian::Big {
495                    if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::ElfV1, CfgAbi::ElfV1) | (LlvmAbi::ElfV2, CfgAbi::ElfV2)
                => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid PowerPC64 big-endian ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
496                        (&self.llvm_abiname, &self.cfg_abi),
497                        (LlvmAbi::ElfV1, CfgAbi::ElfV1) | (LlvmAbi::ElfV2, CfgAbi::ElfV2),
498                        "invalid PowerPC64 big-endian ABI name and `cfg(target_abi)` combination:\n\
499                        ABI name: {}\n\
500                        cfg(target_abi): {}",
501                        self.llvm_abiname,
502                        self.cfg_abi,
503                    );
504                } else {
505                    if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::ElfV2, CfgAbi::ElfV2) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid PowerPC64 little-endian ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
506                        (&self.llvm_abiname, &self.cfg_abi),
507                        (LlvmAbi::ElfV2, CfgAbi::ElfV2),
508                        "invalid PowerPC64 little-endian ABI name and `cfg(target_abi)` combination:\n\
509                        ABI name: {}\n\
510                        cfg(target_abi): {}",
511                        self.llvm_abiname,
512                        self.cfg_abi,
513                    );
514                }
515            }
516            Arch::S390x => {
517                if !(self.llvm_abiname == LlvmAbi::Unspecified) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_abiname` is unused on s390x"))
                }));
};check!(
518                    self.llvm_abiname == LlvmAbi::Unspecified,
519                    "`llvm_abiname` is unused on s390x"
520                );
521                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on s390x"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on s390x");
522                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.rustc_abi,
                &self.cfg_abi) {
            (Some(RustcAbi::Softfloat), CfgAbi::SoftFloat) |
                (None, CfgAbi::Unspecified | CfgAbi::Other(_)) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid s390x Rust-specific ABI and `cfg(target_abi)` combination:\nRust-specific ABI: {0:?}\ncfg(target_abi): {1}",
                            self.rustc_abi, self.cfg_abi))
                }));
};check_matches!(
523                    (&self.rustc_abi, &self.cfg_abi),
524                    (Some(RustcAbi::Softfloat), CfgAbi::SoftFloat)
525                        | (None, CfgAbi::Unspecified | CfgAbi::Other(_)),
526                    "invalid s390x Rust-specific ABI and `cfg(target_abi)` combination:\n\
527                    Rust-specific ABI: {:?}\n\
528                    cfg(target_abi): {}",
529                    self.rustc_abi,
530                    self.cfg_abi,
531                );
532            }
533            Arch::LoongArch32 => {
534                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on LoongArch"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on LoongArch");
535                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on LoongArch"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on LoongArch");
536                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::Ilp32s, CfgAbi::SoftFloat) |
                (LlvmAbi::Ilp32f, CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (LlvmAbi::Ilp32d, CfgAbi::Unspecified | CfgAbi::Other(_)) =>
                true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid LoongArch ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
537                    (&self.llvm_abiname, &self.cfg_abi),
538                    (LlvmAbi::Ilp32s, CfgAbi::SoftFloat)
539                        | (LlvmAbi::Ilp32f, CfgAbi::Unspecified | CfgAbi::Other(_))
540                        | (LlvmAbi::Ilp32d, CfgAbi::Unspecified | CfgAbi::Other(_)),
541                    "invalid LoongArch ABI name and `cfg(target_abi)` combination:\n\
542                     ABI name: {}\n\
543                     cfg(target_abi): {}",
544                    self.llvm_abiname,
545                    self.cfg_abi,
546                );
547            }
548            Arch::LoongArch64 => {
549                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on LoongArch"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on LoongArch");
550                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on LoongArch"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on LoongArch");
551                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::Lp64s, CfgAbi::SoftFloat) |
                (LlvmAbi::Lp64f, CfgAbi::Unspecified | CfgAbi::Other(_)) |
                (LlvmAbi::Lp64d, CfgAbi::Unspecified | CfgAbi::Other(_)) =>
                true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid LoongArch ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
552                    (&self.llvm_abiname, &self.cfg_abi),
553                    (LlvmAbi::Lp64s, CfgAbi::SoftFloat)
554                        | (LlvmAbi::Lp64f, CfgAbi::Unspecified | CfgAbi::Other(_))
555                        | (LlvmAbi::Lp64d, CfgAbi::Unspecified | CfgAbi::Other(_)),
556                    "invalid LoongArch ABI name and `cfg(target_abi)` combination:\n\
557                     ABI name: {}\n\
558                     cfg(target_abi): {}",
559                    self.llvm_abiname,
560                    self.cfg_abi,
561                );
562            }
563            Arch::Mips | Arch::Mips32r6 => {
564                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on MIPS"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on MIPS");
565                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on MIPS"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on MIPS");
566                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::O32, CfgAbi::Unspecified | CfgAbi::Other(_)) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid MIPS ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
567                    (&self.llvm_abiname, &self.cfg_abi),
568                    (LlvmAbi::O32, CfgAbi::Unspecified | CfgAbi::Other(_)),
569                    "invalid MIPS ABI name and `cfg(target_abi)` combination:\n\
570                     ABI name: {}\n\
571                     cfg(target_abi): {}",
572                    self.llvm_abiname,
573                    self.cfg_abi,
574                );
575            }
576            Arch::Mips64 | Arch::Mips64r6 => {
577                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on MIPS"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on MIPS");
578                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on MIPS"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on MIPS");
579                if !#[allow(non_exhaustive_omitted_patterns)] match (&self.llvm_abiname,
                &self.cfg_abi) {
            (LlvmAbi::N64, CfgAbi::Abi64) |
                (LlvmAbi::N32, CfgAbi::Unspecified | CfgAbi::Other(_)) =>
                true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid MIPS ABI name and `cfg(target_abi)` combination:\nABI name: {0}\ncfg(target_abi): {1}",
                            self.llvm_abiname, self.cfg_abi))
                }));
};check_matches!(
580                    (&self.llvm_abiname, &self.cfg_abi),
581                    // No in-tree targets use "n32" but at least for now we let out-of-tree targets
582                    // experiment with that.
583                    (LlvmAbi::N64, CfgAbi::Abi64)
584                        | (LlvmAbi::N32, CfgAbi::Unspecified | CfgAbi::Other(_)),
585                    "invalid MIPS ABI name and `cfg(target_abi)` combination:\n\
586                     ABI name: {}\n\
587                     cfg(target_abi): {}",
588                    self.llvm_abiname,
589                    self.cfg_abi,
590                );
591            }
592            Arch::CSky => {
593                if !(self.llvm_abiname == LlvmAbi::Unspecified) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_abiname` is unused on CSky"))
                }));
};check!(
594                    self.llvm_abiname == LlvmAbi::Unspecified,
595                    "`llvm_abiname` is unused on CSky"
596                );
597                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on CSky"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on CSky");
598                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on CSky"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on CSky");
599                // FIXME: Check that `target_abi` matches the actually configured ABI (v2 vs v2hf).
600                if !#[allow(non_exhaustive_omitted_patterns)] match self.cfg_abi {
            CfgAbi::AbiV2 | CfgAbi::AbiV2Hf => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid `target_abi` for CSky"))
                }));
};check_matches!(
601                    self.cfg_abi,
602                    CfgAbi::AbiV2 | CfgAbi::AbiV2Hf,
603                    "invalid `target_abi` for CSky"
604                );
605            }
606            Arch::Wasm32 | Arch::Wasm64 => {
607                if !(self.llvm_abiname == LlvmAbi::Unspecified) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_abiname` is unused on wasm"))
                }));
};check!(
608                    self.llvm_abiname == LlvmAbi::Unspecified,
609                    "`llvm_abiname` is unused on wasm"
610                );
611                if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on wasm"))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on wasm");
612                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on wasm"))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on wasm");
613                if !#[allow(non_exhaustive_omitted_patterns)] match self.cfg_abi {
            CfgAbi::Unspecified | CfgAbi::Other(_) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("invalid `target_abi` for wasm"))
                }));
};check_matches!(
614                    self.cfg_abi,
615                    CfgAbi::Unspecified | CfgAbi::Other(_),
616                    "invalid `target_abi` for wasm"
617                );
618            }
619            ref arch => {
620                if !self.rustc_abi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`rustc_abi` is unused on {0}",
                            arch))
                }));
};check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on {arch}");
621                // Ensure consistency among built-in targets, but give JSON targets the opportunity
622                // to experiment with these.
623                if kind == TargetKind::Builtin {
624                    if !(self.llvm_abiname == LlvmAbi::Unspecified) {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_abiname` is unused on {0}",
                            arch))
                }));
};check!(
625                        self.llvm_abiname == LlvmAbi::Unspecified,
626                        "`llvm_abiname` is unused on {arch}"
627                    );
628                    if !self.llvm_floatabi.is_none() {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`llvm_floatabi` is unused on {0}",
                            arch))
                }));
};check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on {arch}");
629                    if !#[allow(non_exhaustive_omitted_patterns)] match self.cfg_abi {
            CfgAbi::Unspecified | CfgAbi::Other(_) => true,
            _ => false,
        } {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`target_abi` is unused on {0}",
                            arch))
                }));
};check_matches!(
630                        self.cfg_abi,
631                        CfgAbi::Unspecified | CfgAbi::Other(_),
632                        "`target_abi` is unused on {arch}"
633                    );
634                }
635            }
636        }
637
638        // Check that the target cpu constraints make sense.
639        if self.need_explicit_cpu {
640            if !self.requires_consistent_cpu {
    return Err(::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("if `need_explicit_cpu` is set, then `requires_consistent_cpu` must be set"))
                }));
};check!(
641                self.requires_consistent_cpu,
642                "if `need_explicit_cpu` is set, then `requires_consistent_cpu` must be set"
643            );
644        }
645
646        // Check that the given target-features string makes some basic sense.
647        if !self.features.is_empty() {
648            let mut features_enabled = FxHashSet::default();
649            let mut features_disabled = FxHashSet::default();
650            for feat in self.features.split(',') {
651                if let Some(feat) = feat.strip_prefix("+") {
652                    features_enabled.insert(feat);
653                    if features_disabled.contains(feat) {
654                        return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("target feature `{0}` is both enabled and disabled",
                feat))
    })format!(
655                            "target feature `{feat}` is both enabled and disabled"
656                        ));
657                    }
658                } else if let Some(feat) = feat.strip_prefix("-") {
659                    features_disabled.insert(feat);
660                    if features_enabled.contains(feat) {
661                        return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("target feature `{0}` is both enabled and disabled",
                feat))
    })format!(
662                            "target feature `{feat}` is both enabled and disabled"
663                        ));
664                    }
665                } else {
666                    return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("target feature `{0}` is invalid, must start with `+` or `-`",
                feat))
    })format!(
667                        "target feature `{feat}` is invalid, must start with `+` or `-`"
668                    ));
669                }
670            }
671            // Check that we don't mis-set any of the ABI-relevant features.
672            let abi_feature_constraints = self.abi_required_features();
673            for feat in abi_feature_constraints.required {
674                // The feature might be enabled by default so we can't *require* it to show up.
675                // But it must not be *disabled*.
676                if features_disabled.contains(feat) {
677                    return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("target feature `{0}` is required by the ABI but gets disabled in target spec",
                feat))
    })format!(
678                        "target feature `{feat}` is required by the ABI but gets disabled in target spec"
679                    ));
680                }
681            }
682            for feat in abi_feature_constraints.incompatible {
683                // The feature might be disabled by default so we can't *require* it to show up.
684                // But it must not be *enabled*.
685                if features_enabled.contains(feat) {
686                    return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("target feature `{0}` is incompatible with the ABI but gets enabled in target spec",
                feat))
    })format!(
687                        "target feature `{feat}` is incompatible with the ABI but gets enabled in target spec"
688                    ));
689                }
690            }
691        }
692
693        Ok(())
694    }
695}