/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 | | } |