Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/target-lexicon-0.12.15/src/triple.rs
Line
Count
Source (jump to first uncovered line)
1
// This file defines the `Triple` type and support code shared by all targets.
2
3
use crate::data_model::CDataModel;
4
use crate::parse_error::ParseError;
5
use crate::targets::{
6
    default_binary_format, Architecture, ArmArchitecture, BinaryFormat, Environment,
7
    OperatingSystem, Riscv32Architecture, Vendor,
8
};
9
#[cfg(not(feature = "std"))]
10
use alloc::borrow::ToOwned;
11
use core::fmt;
12
use core::str::FromStr;
13
14
/// The target memory endianness.
15
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
16
#[allow(missing_docs)]
17
pub enum Endianness {
18
    Little,
19
    Big,
20
}
21
22
/// The width of a pointer (in the default address space).
23
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
24
#[allow(missing_docs)]
25
pub enum PointerWidth {
26
    U16,
27
    U32,
28
    U64,
29
}
30
31
impl PointerWidth {
32
    /// Return the number of bits in a pointer.
33
814k
    pub fn bits(self) -> u8 {
34
814k
        match self {
35
0
            PointerWidth::U16 => 16,
36
0
            PointerWidth::U32 => 32,
37
814k
            PointerWidth::U64 => 64,
38
        }
39
814k
    }
<target_lexicon::triple::PointerWidth>::bits
Line
Count
Source
33
69.9k
    pub fn bits(self) -> u8 {
34
69.9k
        match self {
35
0
            PointerWidth::U16 => 16,
36
0
            PointerWidth::U32 => 32,
37
69.9k
            PointerWidth::U64 => 64,
38
        }
39
69.9k
    }
<target_lexicon::triple::PointerWidth>::bits
Line
Count
Source
33
744k
    pub fn bits(self) -> u8 {
34
744k
        match self {
35
0
            PointerWidth::U16 => 16,
36
0
            PointerWidth::U32 => 32,
37
744k
            PointerWidth::U64 => 64,
38
        }
39
744k
    }
Unexecuted instantiation: <target_lexicon::triple::PointerWidth>::bits
Unexecuted instantiation: <target_lexicon::triple::PointerWidth>::bits
40
41
    /// Return the number of bytes in a pointer.
42
    ///
43
    /// For these purposes, there are 8 bits in a byte.
44
237k
    pub fn bytes(self) -> u8 {
45
237k
        match self {
46
0
            PointerWidth::U16 => 2,
47
0
            PointerWidth::U32 => 4,
48
237k
            PointerWidth::U64 => 8,
49
        }
50
237k
    }
<target_lexicon::triple::PointerWidth>::bytes
Line
Count
Source
44
97.8k
    pub fn bytes(self) -> u8 {
45
97.8k
        match self {
46
0
            PointerWidth::U16 => 2,
47
0
            PointerWidth::U32 => 4,
48
97.8k
            PointerWidth::U64 => 8,
49
        }
50
97.8k
    }
<target_lexicon::triple::PointerWidth>::bytes
Line
Count
Source
44
139k
    pub fn bytes(self) -> u8 {
45
139k
        match self {
46
0
            PointerWidth::U16 => 2,
47
0
            PointerWidth::U32 => 4,
48
139k
            PointerWidth::U64 => 8,
49
        }
50
139k
    }
Unexecuted instantiation: <target_lexicon::triple::PointerWidth>::bytes
Unexecuted instantiation: <target_lexicon::triple::PointerWidth>::bytes
51
}
52
53
/// The calling convention, which specifies things like which registers are
54
/// used for passing arguments, which registers are callee-saved, and so on.
55
#[cfg_attr(feature = "rust_1_40", non_exhaustive)]
56
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
57
pub enum CallingConvention {
58
    /// "System V", which is used on most Unix-like platfoms. Note that the
59
    /// specific conventions vary between hardware architectures; for example,
60
    /// x86-32's "System V" is entirely different from x86-64's "System V".
61
    SystemV,
62
63
    /// The WebAssembly C ABI.
64
    /// https://github.com/WebAssembly/tool-conventions/blob/master/BasicCABI.md
65
    WasmBasicCAbi,
66
67
    /// "Windows Fastcall", which is used on Windows. Note that like "System V",
68
    /// this varies between hardware architectures. On x86-32 it describes what
69
    /// Windows documentation calls "fastcall", and on x86-64 it describes what
70
    /// Windows documentation often just calls the Windows x64 calling convention
71
    /// (though the compiler still recognizes "fastcall" as an alias for it).
72
    WindowsFastcall,
73
74
    /// Apple Aarch64 platforms use their own variant of the common Aarch64
75
    /// calling convention.
76
    ///
77
    /// <https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms>
78
    AppleAarch64,
79
}
80
81
/// A target "triple". Historically such things had three fields, though they've
82
/// added additional fields over time.
83
///
84
/// Note that `Triple` doesn't implement `Default` itself. If you want a type
85
/// which defaults to the host triple, or defaults to unknown-unknown-unknown,
86
/// use `DefaultToHost` or `DefaultToUnknown`, respectively.
87
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
88
pub struct Triple {
89
    /// The "architecture" (and sometimes the subarchitecture).
90
    pub architecture: Architecture,
91
    /// The "vendor" (whatever that means).
92
    pub vendor: Vendor,
93
    /// The "operating system" (sometimes also the environment).
94
    pub operating_system: OperatingSystem,
95
    /// The "environment" on top of the operating system (often omitted for
96
    /// operating systems with a single predominant environment).
97
    pub environment: Environment,
98
    /// The "binary format" (rarely used).
99
    pub binary_format: BinaryFormat,
100
}
101
102
impl Triple {
103
    /// Return the endianness of this target's architecture.
104
28.4k
    pub fn endianness(&self) -> Result<Endianness, ()> {
105
28.4k
        self.architecture.endianness()
106
28.4k
    }
107
108
    /// Return the pointer width of this target's architecture.
109
    ///
110
    /// This function is aware of x32 and ilp32 ABIs on 64-bit architectures.
111
914k
    pub fn pointer_width(&self) -> Result<PointerWidth, ()> {
112
914k
        // Some ABIs have a different pointer width than the CPU architecture.
113
914k
        match self.environment {
114
0
            Environment::Gnux32 | Environment::GnuIlp32 => return Ok(PointerWidth::U32),
115
914k
            _ => {}
116
914k
        }
117
914k
118
914k
        self.architecture.pointer_width()
119
914k
    }
120
121
    /// Return the default calling convention for the given target triple.
122
200k
    pub fn default_calling_convention(&self) -> Result<CallingConvention, ()> {
123
200k
        Ok(match self.operating_system {
124
            OperatingSystem::Darwin
125
            | OperatingSystem::Ios
126
            | OperatingSystem::Tvos
127
            | OperatingSystem::MacOSX { .. }
128
0
            | OperatingSystem::Watchos => match self.architecture {
129
0
                Architecture::Aarch64(_) => CallingConvention::AppleAarch64,
130
0
                _ => CallingConvention::SystemV,
131
            },
132
            OperatingSystem::Aix
133
            | OperatingSystem::Bitrig
134
            | OperatingSystem::Cloudabi
135
            | OperatingSystem::Dragonfly
136
            | OperatingSystem::Freebsd
137
            | OperatingSystem::Fuchsia
138
            | OperatingSystem::Haiku
139
            | OperatingSystem::Hermit
140
            | OperatingSystem::Hurd
141
            | OperatingSystem::L4re
142
            | OperatingSystem::Linux
143
            | OperatingSystem::Netbsd
144
            | OperatingSystem::Openbsd
145
            | OperatingSystem::Redox
146
200k
            | OperatingSystem::Solaris => CallingConvention::SystemV,
147
0
            OperatingSystem::Windows => CallingConvention::WindowsFastcall,
148
            OperatingSystem::Nebulet
149
            | OperatingSystem::Emscripten
150
            | OperatingSystem::Wasi
151
0
            | OperatingSystem::Unknown => match self.architecture {
152
0
                Architecture::Wasm32 => CallingConvention::WasmBasicCAbi,
153
0
                _ => return Err(()),
154
            },
155
0
            _ => return Err(()),
156
        })
157
200k
    }
<target_lexicon::triple::Triple>::default_calling_convention
Line
Count
Source
122
8.54k
    pub fn default_calling_convention(&self) -> Result<CallingConvention, ()> {
123
8.54k
        Ok(match self.operating_system {
124
            OperatingSystem::Darwin
125
            | OperatingSystem::Ios
126
            | OperatingSystem::Tvos
127
            | OperatingSystem::MacOSX { .. }
128
0
            | OperatingSystem::Watchos => match self.architecture {
129
0
                Architecture::Aarch64(_) => CallingConvention::AppleAarch64,
130
0
                _ => CallingConvention::SystemV,
131
            },
132
            OperatingSystem::Aix
133
            | OperatingSystem::Bitrig
134
            | OperatingSystem::Cloudabi
135
            | OperatingSystem::Dragonfly
136
            | OperatingSystem::Freebsd
137
            | OperatingSystem::Fuchsia
138
            | OperatingSystem::Haiku
139
            | OperatingSystem::Hermit
140
            | OperatingSystem::Hurd
141
            | OperatingSystem::L4re
142
            | OperatingSystem::Linux
143
            | OperatingSystem::Netbsd
144
            | OperatingSystem::Openbsd
145
            | OperatingSystem::Redox
146
8.54k
            | OperatingSystem::Solaris => CallingConvention::SystemV,
147
0
            OperatingSystem::Windows => CallingConvention::WindowsFastcall,
148
            OperatingSystem::Nebulet
149
            | OperatingSystem::Emscripten
150
            | OperatingSystem::Wasi
151
0
            | OperatingSystem::Unknown => match self.architecture {
152
0
                Architecture::Wasm32 => CallingConvention::WasmBasicCAbi,
153
0
                _ => return Err(()),
154
            },
155
0
            _ => return Err(()),
156
        })
157
8.54k
    }
<target_lexicon::triple::Triple>::default_calling_convention
Line
Count
Source
122
149k
    pub fn default_calling_convention(&self) -> Result<CallingConvention, ()> {
123
149k
        Ok(match self.operating_system {
124
            OperatingSystem::Darwin
125
            | OperatingSystem::Ios
126
            | OperatingSystem::Tvos
127
            | OperatingSystem::MacOSX { .. }
128
0
            | OperatingSystem::Watchos => match self.architecture {
129
0
                Architecture::Aarch64(_) => CallingConvention::AppleAarch64,
130
0
                _ => CallingConvention::SystemV,
131
            },
132
            OperatingSystem::Aix
133
            | OperatingSystem::Bitrig
134
            | OperatingSystem::Cloudabi
135
            | OperatingSystem::Dragonfly
136
            | OperatingSystem::Freebsd
137
            | OperatingSystem::Fuchsia
138
            | OperatingSystem::Haiku
139
            | OperatingSystem::Hermit
140
            | OperatingSystem::Hurd
141
            | OperatingSystem::L4re
142
            | OperatingSystem::Linux
143
            | OperatingSystem::Netbsd
144
            | OperatingSystem::Openbsd
145
            | OperatingSystem::Redox
146
149k
            | OperatingSystem::Solaris => CallingConvention::SystemV,
147
0
            OperatingSystem::Windows => CallingConvention::WindowsFastcall,
148
            OperatingSystem::Nebulet
149
            | OperatingSystem::Emscripten
150
            | OperatingSystem::Wasi
151
0
            | OperatingSystem::Unknown => match self.architecture {
152
0
                Architecture::Wasm32 => CallingConvention::WasmBasicCAbi,
153
0
                _ => return Err(()),
154
            },
155
0
            _ => return Err(()),
156
        })
157
149k
    }
Unexecuted instantiation: <target_lexicon::triple::Triple>::default_calling_convention
<target_lexicon::triple::Triple>::default_calling_convention
Line
Count
Source
122
23.5k
    pub fn default_calling_convention(&self) -> Result<CallingConvention, ()> {
123
23.5k
        Ok(match self.operating_system {
124
            OperatingSystem::Darwin
125
            | OperatingSystem::Ios
126
            | OperatingSystem::Tvos
127
            | OperatingSystem::MacOSX { .. }
128
0
            | OperatingSystem::Watchos => match self.architecture {
129
0
                Architecture::Aarch64(_) => CallingConvention::AppleAarch64,
130
0
                _ => CallingConvention::SystemV,
131
            },
132
            OperatingSystem::Aix
133
            | OperatingSystem::Bitrig
134
            | OperatingSystem::Cloudabi
135
            | OperatingSystem::Dragonfly
136
            | OperatingSystem::Freebsd
137
            | OperatingSystem::Fuchsia
138
            | OperatingSystem::Haiku
139
            | OperatingSystem::Hermit
140
            | OperatingSystem::Hurd
141
            | OperatingSystem::L4re
142
            | OperatingSystem::Linux
143
            | OperatingSystem::Netbsd
144
            | OperatingSystem::Openbsd
145
            | OperatingSystem::Redox
146
23.5k
            | OperatingSystem::Solaris => CallingConvention::SystemV,
147
0
            OperatingSystem::Windows => CallingConvention::WindowsFastcall,
148
            OperatingSystem::Nebulet
149
            | OperatingSystem::Emscripten
150
            | OperatingSystem::Wasi
151
0
            | OperatingSystem::Unknown => match self.architecture {
152
0
                Architecture::Wasm32 => CallingConvention::WasmBasicCAbi,
153
0
                _ => return Err(()),
154
            },
155
0
            _ => return Err(()),
156
        })
157
23.5k
    }
Unexecuted instantiation: <target_lexicon::triple::Triple>::default_calling_convention
<target_lexicon::triple::Triple>::default_calling_convention
Line
Count
Source
122
18.5k
    pub fn default_calling_convention(&self) -> Result<CallingConvention, ()> {
123
18.5k
        Ok(match self.operating_system {
124
            OperatingSystem::Darwin
125
            | OperatingSystem::Ios
126
            | OperatingSystem::Tvos
127
            | OperatingSystem::MacOSX { .. }
128
0
            | OperatingSystem::Watchos => match self.architecture {
129
0
                Architecture::Aarch64(_) => CallingConvention::AppleAarch64,
130
0
                _ => CallingConvention::SystemV,
131
            },
132
            OperatingSystem::Aix
133
            | OperatingSystem::Bitrig
134
            | OperatingSystem::Cloudabi
135
            | OperatingSystem::Dragonfly
136
            | OperatingSystem::Freebsd
137
            | OperatingSystem::Fuchsia
138
            | OperatingSystem::Haiku
139
            | OperatingSystem::Hermit
140
            | OperatingSystem::Hurd
141
            | OperatingSystem::L4re
142
            | OperatingSystem::Linux
143
            | OperatingSystem::Netbsd
144
            | OperatingSystem::Openbsd
145
            | OperatingSystem::Redox
146
18.5k
            | OperatingSystem::Solaris => CallingConvention::SystemV,
147
0
            OperatingSystem::Windows => CallingConvention::WindowsFastcall,
148
            OperatingSystem::Nebulet
149
            | OperatingSystem::Emscripten
150
            | OperatingSystem::Wasi
151
0
            | OperatingSystem::Unknown => match self.architecture {
152
0
                Architecture::Wasm32 => CallingConvention::WasmBasicCAbi,
153
0
                _ => return Err(()),
154
            },
155
0
            _ => return Err(()),
156
        })
157
18.5k
    }
158
159
    /// The C data model for a given target. If the model is not known, returns `Err(())`.
160
0
    pub fn data_model(&self) -> Result<CDataModel, ()> {
161
0
        match self.pointer_width()? {
162
            PointerWidth::U64 => {
163
0
                if self.operating_system == OperatingSystem::Windows {
164
0
                    Ok(CDataModel::LLP64)
165
0
                } else if self.default_calling_convention() == Ok(CallingConvention::SystemV)
166
0
                    || self.architecture == Architecture::Wasm64
167
0
                    || self.default_calling_convention() == Ok(CallingConvention::AppleAarch64)
168
                {
169
0
                    Ok(CDataModel::LP64)
170
                } else {
171
0
                    Err(())
172
                }
173
            }
174
            PointerWidth::U32 => {
175
0
                if self.operating_system == OperatingSystem::Windows
176
0
                    || self.default_calling_convention() == Ok(CallingConvention::SystemV)
177
0
                    || self.architecture == Architecture::Wasm32
178
                {
179
0
                    Ok(CDataModel::ILP32)
180
                } else {
181
0
                    Err(())
182
                }
183
            }
184
            // TODO: on 16-bit machines there is usually a distinction
185
            // between near-pointers and far-pointers.
186
            // Additionally, code pointers sometimes have a different size than data pointers.
187
            // We don't handle this case.
188
0
            PointerWidth::U16 => Err(()),
189
        }
190
0
    }
191
192
    /// Return a `Triple` with all unknown fields.
193
0
    pub fn unknown() -> Self {
194
0
        Self {
195
0
            architecture: Architecture::Unknown,
196
0
            vendor: Vendor::Unknown,
197
0
            operating_system: OperatingSystem::Unknown,
198
0
            environment: Environment::Unknown,
199
0
            binary_format: BinaryFormat::Unknown,
200
0
        }
201
0
    }
202
}
203
204
impl fmt::Display for Triple {
205
171k
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206
171k
        if let Some(res) = self.special_case_display(f) {
207
0
            return res;
208
171k
        }
209
171k
210
171k
        let implied_binary_format = default_binary_format(&self);
211
171k
212
171k
        write!(f, "{}", self.architecture)?;
213
171k
        if self.vendor == Vendor::Unknown
214
171k
            && (self.environment != Environment::HermitKernel
215
171k
                && self.environment != Environment::LinuxKernel)
216
171k
            && ((self.operating_system == OperatingSystem::Linux
217
171k
                && (self.environment == Environment::Android
218
171k
                    || self.environment == Environment::Androideabi
219
171k
                    || self.environment == Environment::Kernel))
220
171k
                || self.operating_system == OperatingSystem::Wasi
221
171k
                || self.operating_system == OperatingSystem::WasiP1
222
171k
                || self.operating_system == OperatingSystem::WasiP2
223
171k
                || (self.operating_system == OperatingSystem::None_
224
0
                    && (self.architecture == Architecture::Arm(ArmArchitecture::Armv4t)
225
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Armv5te)
226
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Armebv7r)
227
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Armv7a)
228
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Armv7r)
229
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Armv8r)
230
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv4t)
231
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv5te)
232
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv6m)
233
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7em)
234
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7m)
235
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mBase)
236
0
                        || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mMain)
237
0
                        || self.architecture == Architecture::Msp430)))
238
        {
239
            // As a special case, omit the vendor for Android, Wasi, and sometimes
240
            // None_, depending on the hardware architecture. This logic is entirely
241
            // ad-hoc, and is just sufficient to handle the current set of recognized
242
            // triples.
243
0
            write!(f, "-{}", self.operating_system)?;
244
171k
        } else if self.architecture.is_clever() && self.operating_system == OperatingSystem::Unknown
245
        {
246
0
            write!(f, "-{}", self.vendor)?;
247
        } else {
248
171k
            write!(f, "-{}-{}", self.vendor, self.operating_system)?;
249
        }
250
251
171k
        match (&self.vendor, self.operating_system, self.environment) {
252
            (Vendor::Nintendo, OperatingSystem::Horizon, Environment::Newlib)
253
0
            | (Vendor::Espressif, OperatingSystem::Espidf, Environment::Newlib) => {
254
0
                // The triple representations of these platforms don't have an environment field.
255
0
            }
256
0
            (_, _, Environment::Unknown) => {
257
0
                // Don't print out the environment if it is unknown.
258
0
            }
259
            _ => {
260
171k
                write!(f, "-{}", self.environment)?;
261
            }
262
        }
263
264
171k
        if self.binary_format != implied_binary_format || show_binary_format_with_no_os(self) {
265
            // As a special case, omit a non-default binary format for some
266
            // targets which happen to exclude it.
267
0
            write!(f, "-{}", self.binary_format)?;
268
171k
        }
269
171k
        Ok(())
270
171k
    }
271
}
272
273
171k
fn show_binary_format_with_no_os(triple: &Triple) -> bool {
274
171k
    if triple.binary_format == BinaryFormat::Unknown {
275
0
        return false;
276
171k
    }
277
171k
278
171k
    #[cfg(feature = "arch_zkasm")]
279
171k
    {
280
171k
        if triple.architecture == Architecture::ZkAsm {
281
171k
            return false;
282
171k
        }
283
171k
    }
284
171k
285
171k
    triple.environment != Environment::Eabi
286
171k
        && triple.environment != Environment::Eabihf
287
171k
        && triple.environment != Environment::Sgx
288
171k
        && triple.architecture != Architecture::Avr
289
171k
        && triple.architecture != Architecture::Wasm32
290
171k
        && triple.architecture != Architecture::Wasm64
291
171k
        && (triple.operating_system == OperatingSystem::None_
292
171k
            || triple.operating_system == OperatingSystem::Unknown)
293
171k
}
294
295
impl FromStr for Triple {
296
    type Err = ParseError;
297
298
0
    fn from_str(s: &str) -> Result<Self, Self::Err> {
299
0
        if let Some(triple) = Triple::special_case_from_str(s) {
300
0
            return Ok(triple);
301
0
        }
302
0
303
0
        let mut parts = s.split('-');
304
0
        let mut result = Self::unknown();
305
0
        let mut current_part;
306
0
307
0
        current_part = parts.next();
308
0
        if let Some(s) = current_part {
309
0
            if let Ok(architecture) = Architecture::from_str(s) {
310
0
                result.architecture = architecture;
311
0
                current_part = parts.next();
312
0
            } else {
313
                // Insist that the triple start with a valid architecture.
314
0
                return Err(ParseError::UnrecognizedArchitecture(s.to_owned()));
315
            }
316
0
        }
317
318
0
        let mut has_vendor = false;
319
0
        let mut has_operating_system = false;
320
0
        if let Some(s) = current_part {
321
0
            if let Ok(vendor) = Vendor::from_str(s) {
322
0
                has_vendor = true;
323
0
                result.vendor = vendor;
324
0
                current_part = parts.next();
325
0
            }
326
0
        }
327
328
0
        if !has_operating_system {
329
0
            if let Some(s) = current_part {
330
0
                if let Ok(operating_system) = OperatingSystem::from_str(s) {
331
0
                    has_operating_system = true;
332
0
                    result.operating_system = operating_system;
333
0
                    current_part = parts.next();
334
0
                }
335
0
            }
336
0
        }
337
338
0
        let mut has_environment = false;
339
0
340
0
        if !has_environment {
341
0
            if let Some(s) = current_part {
342
0
                if let Ok(environment) = Environment::from_str(s) {
343
0
                    has_environment = true;
344
0
                    result.environment = environment;
345
0
                    current_part = parts.next();
346
0
                }
347
0
            }
348
0
        }
349
350
0
        let mut has_binary_format = false;
351
0
        if let Some(s) = current_part {
352
0
            if let Ok(binary_format) = BinaryFormat::from_str(s) {
353
0
                has_binary_format = true;
354
0
                result.binary_format = binary_format;
355
0
                current_part = parts.next();
356
0
            }
357
0
        }
358
359
        // The binary format is frequently omitted; if that's the case here,
360
        // infer it from the other fields.
361
0
        if !has_binary_format {
362
0
            result.binary_format = default_binary_format(&result);
363
0
        }
364
365
0
        if let Some(s) = current_part {
366
            Err(
367
0
                if !has_vendor && !has_operating_system && !has_environment && !has_binary_format {
368
0
                    ParseError::UnrecognizedVendor(s.to_owned())
369
0
                } else if !has_operating_system && !has_environment && !has_binary_format {
370
0
                    ParseError::UnrecognizedOperatingSystem(s.to_owned())
371
0
                } else if !has_environment && !has_binary_format {
372
0
                    ParseError::UnrecognizedEnvironment(s.to_owned())
373
0
                } else if !has_binary_format {
374
0
                    ParseError::UnrecognizedBinaryFormat(s.to_owned())
375
                } else {
376
0
                    ParseError::UnrecognizedField(s.to_owned())
377
                },
378
            )
379
        } else {
380
0
            Ok(result)
381
        }
382
0
    }
383
}
384
385
impl Triple {
386
    /// Handle special cases in the `Display` implementation.
387
171k
    fn special_case_display(&self, f: &mut fmt::Formatter) -> Option<fmt::Result> {
388
0
        let res = match self {
389
            Triple {
390
                architecture: Architecture::Arm(ArmArchitecture::Armv6k),
391
                vendor: Vendor::Nintendo,
392
                operating_system: OperatingSystem::Horizon,
393
                ..
394
0
            } => write!(f, "{}-{}-3ds", self.architecture, self.vendor),
395
            Triple {
396
                architecture: Architecture::Riscv32(Riscv32Architecture::Riscv32imc),
397
                vendor: Vendor::Espressif,
398
                operating_system: OperatingSystem::Espidf,
399
                ..
400
0
            } => write!(f, "{}-esp-{}", self.architecture, self.operating_system),
401
171k
            _ => return None,
402
        };
403
0
        Some(res)
404
171k
    }
405
406
    /// Handle special cases in the `FromStr` implementation.
407
0
    fn special_case_from_str(s: &str) -> Option<Self> {
408
0
        let mut triple = Triple::unknown();
409
0
410
0
        match s {
411
0
            "armv6k-nintendo-3ds" => {
412
0
                triple.architecture = Architecture::Arm(ArmArchitecture::Armv6k);
413
0
                triple.vendor = Vendor::Nintendo;
414
0
                triple.operating_system = OperatingSystem::Horizon;
415
0
                triple.environment = Environment::Newlib;
416
0
                triple.binary_format = default_binary_format(&triple);
417
0
            }
418
0
            "riscv32imc-esp-espidf" => {
419
0
                triple.architecture = Architecture::Riscv32(Riscv32Architecture::Riscv32imc);
420
0
                triple.vendor = Vendor::Espressif;
421
0
                triple.operating_system = OperatingSystem::Espidf;
422
0
                triple.environment = Environment::Newlib;
423
0
                triple.binary_format = default_binary_format(&triple);
424
0
            }
425
0
            _ => return None,
426
        }
427
428
0
        Some(triple)
429
0
    }
430
}
431
432
/// A convenient syntax for triple literals.
433
///
434
/// This currently expands to code that just calls `Triple::from_str` and does
435
/// an `expect`, though in the future it would be cool to use procedural macros
436
/// or so to report errors at compile time instead.
437
#[macro_export]
438
macro_rules! triple {
439
    ($str:tt) => {
440
        <$crate::Triple as core::str::FromStr>::from_str($str).expect("invalid triple literal")
441
    };
442
}
443
444
#[cfg(test)]
445
mod tests {
446
    use super::*;
447
448
    #[test]
449
    fn parse_errors() {
450
        assert_eq!(
451
            Triple::from_str(""),
452
            Err(ParseError::UnrecognizedArchitecture("".to_owned()))
453
        );
454
        assert_eq!(
455
            Triple::from_str("foo"),
456
            Err(ParseError::UnrecognizedArchitecture("foo".to_owned()))
457
        );
458
        assert_eq!(
459
            Triple::from_str("unknown-unknown-foo"),
460
            Err(ParseError::UnrecognizedOperatingSystem("foo".to_owned()))
461
        );
462
        assert_eq!(
463
            Triple::from_str("unknown-unknown-unknown-foo"),
464
            Err(ParseError::UnrecognizedEnvironment("foo".to_owned()))
465
        );
466
        assert_eq!(
467
            Triple::from_str("unknown-unknown-unknown-unknown-foo"),
468
            Err(ParseError::UnrecognizedBinaryFormat("foo".to_owned()))
469
        );
470
        assert_eq!(
471
            Triple::from_str("unknown-unknown-unknown-unknown-unknown-foo"),
472
            Err(ParseError::UnrecognizedField("foo".to_owned()))
473
        );
474
    }
475
476
    #[test]
477
    fn defaults() {
478
        assert_eq!(
479
            Triple::from_str("unknown-unknown-unknown"),
480
            Ok(Triple::unknown())
481
        );
482
        assert_eq!(
483
            Triple::from_str("unknown-unknown-unknown-unknown"),
484
            Ok(Triple::unknown())
485
        );
486
        assert_eq!(
487
            Triple::from_str("unknown-unknown-unknown-unknown-unknown"),
488
            Ok(Triple::unknown())
489
        );
490
    }
491
492
    #[test]
493
    fn unknown_properties() {
494
        assert_eq!(Triple::unknown().endianness(), Err(()));
495
        assert_eq!(Triple::unknown().pointer_width(), Err(()));
496
        assert_eq!(Triple::unknown().default_calling_convention(), Err(()));
497
    }
498
499
    #[test]
500
    fn apple_calling_convention() {
501
        for triple in &[
502
            "aarch64-apple-darwin",
503
            "aarch64-apple-ios",
504
            "aarch64-apple-ios-macabi",
505
            "aarch64-apple-tvos",
506
            "aarch64-apple-watchos",
507
        ] {
508
            let triple = Triple::from_str(triple).unwrap();
509
            assert_eq!(
510
                triple.default_calling_convention().unwrap(),
511
                CallingConvention::AppleAarch64
512
            );
513
            assert_eq!(triple.data_model().unwrap(), CDataModel::LP64);
514
        }
515
516
        for triple in &["aarch64-linux-android", "x86_64-apple-ios"] {
517
            assert_eq!(
518
                Triple::from_str(triple)
519
                    .unwrap()
520
                    .default_calling_convention()
521
                    .unwrap(),
522
                CallingConvention::SystemV
523
            );
524
        }
525
    }
526
527
    #[test]
528
    fn p32_abi() {
529
        // Test that special 32-bit pointer ABIs on 64-bit architectures are
530
        // reported as having 32-bit pointers.
531
        for triple in &[
532
            "x86_64-unknown-linux-gnux32",
533
            "aarch64_be-unknown-linux-gnu_ilp32",
534
            "aarch64-unknown-linux-gnu_ilp32",
535
        ] {
536
            assert_eq!(
537
                Triple::from_str(triple).unwrap().pointer_width().unwrap(),
538
                PointerWidth::U32
539
            );
540
        }
541
542
        // Test that the corresponding ABIs have 64-bit pointers.
543
        for triple in &[
544
            "x86_64-unknown-linux-gnu",
545
            "aarch64_be-unknown-linux-gnu",
546
            "aarch64-unknown-linux-gnu",
547
        ] {
548
            assert_eq!(
549
                Triple::from_str(triple).unwrap().pointer_width().unwrap(),
550
                PointerWidth::U64
551
            );
552
        }
553
    }
554
}