diff options
Diffstat (limited to 'third_party/rust/target-lexicon')
-rw-r--r-- | third_party/rust/target-lexicon/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/Cargo.lock | 6 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/Cargo.toml | 33 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/LICENSE | 220 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/README.md | 20 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/build.rs | 191 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/examples/host.rs | 12 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/examples/misc.rs | 14 | ||||
-rwxr-xr-x | third_party/rust/target-lexicon/scripts/rust-targets.sh | 7 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/src/data_model.rs | 105 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/src/host.rs | 56 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/src/lib.rs | 57 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/src/parse_error.rs | 34 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/src/targets.rs | 1445 | ||||
-rw-r--r-- | third_party/rust/target-lexicon/src/triple.rs | 372 |
15 files changed, 2573 insertions, 0 deletions
diff --git a/third_party/rust/target-lexicon/.cargo-checksum.json b/third_party/rust/target-lexicon/.cargo-checksum.json new file mode 100644 index 0000000000..9f8a431d3e --- /dev/null +++ b/third_party/rust/target-lexicon/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"764401bfb5ba50ed42c6b00274fd4444cefa31ef40183c224b11ed38abc2e68f","Cargo.toml":"d293a3613d3af95f1a0e49a08bb2c73ca0adf0ef375ffbdd4f7866c96500f0dc","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","README.md":"c3467056d91be3f59562158ee9604c729b5b5f473efbefb036032803eb76809e","build.rs":"03132c64805a8acee491ca7c40d090f20a53295967a442e08d9ab15acff9d076","examples/host.rs":"503bafddfb372123fe4dc0e7b8037808beb5bfe6df60c00d3315922bd3792c6c","examples/misc.rs":"49a579845450b7b020ed5c97dca142fc548725893cbc82f6f750ee0caab2beca","scripts/rust-targets.sh":"89564342916321c5bc35e772d374a7f0af22cc9ae6dcc0027eca48d2269f18cb","src/data_model.rs":"a33e047aadd048bc5846c97351df831d34fbd2321a6560dd71868875101ba3a8","src/host.rs":"fb543df4f362e9119a58523563e453110f4e3a426f0995911d0ca386657cf1d9","src/lib.rs":"2f4874d504386b0ace62e7089a114c8ee0426c2ff0ee293ee3af8c67b92e670b","src/parse_error.rs":"b3735eabc0fd0a9dfdd6375662f20ec96a79852a00a05a98fb2e421545285e53","src/targets.rs":"0f6b07b3e7bc19e562c85a32a786cf9f551f8ea15ceef486bbd5c8cb28d11bb8","src/triple.rs":"da5705a96c6cd4cd03696ad9612e1a8a59cd9def59f16750149edbcdd1461fb4"},"package":"fe2635952a442a01fd4cb53d98858b5e4bb461b02c0d111f22f31772e3e7a8b2"}
\ No newline at end of file diff --git a/third_party/rust/target-lexicon/Cargo.lock b/third_party/rust/target-lexicon/Cargo.lock new file mode 100644 index 0000000000..dafdbc10d2 --- /dev/null +++ b/third_party/rust/target-lexicon/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "target-lexicon" +version = "0.11.0" + diff --git a/third_party/rust/target-lexicon/Cargo.toml b/third_party/rust/target-lexicon/Cargo.toml new file mode 100644 index 0000000000..6ced25170a --- /dev/null +++ b/third_party/rust/target-lexicon/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "target-lexicon" +version = "0.11.0" +authors = ["Dan Gohman <sunfish@mozilla.com>"] +description = "Targeting utilities for compilers and related tools" +documentation = "https://docs.rs/target-lexicon/" +readme = "README.md" +keywords = ["target", "host", "triple", "compiler", "jit"] +categories = ["no-std"] +license = "Apache-2.0 WITH LLVM-exception" +repository = "https://github.com/CraneStation/target-lexicon" + +[features] +default = [] +std = [] +[badges.maintenance] +status = "passively-maintained" + +[badges.travis-ci] +repository = "CraneStation/target-lexicon" diff --git a/third_party/rust/target-lexicon/LICENSE b/third_party/rust/target-lexicon/LICENSE new file mode 100644 index 0000000000..f9d81955f4 --- /dev/null +++ b/third_party/rust/target-lexicon/LICENSE @@ -0,0 +1,220 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/third_party/rust/target-lexicon/README.md b/third_party/rust/target-lexicon/README.md new file mode 100644 index 0000000000..2e539eb716 --- /dev/null +++ b/third_party/rust/target-lexicon/README.md @@ -0,0 +1,20 @@ +This is a library for managing targets for compilers and related tools. + +Currently, the main feature is support for decoding "triples", which +are strings that identify a particular target configuration. They're named +"triples" because historically they contained three fields, though over time +they've added additional fields. This library provides a `Triple` struct +containing enums for each of fields of a triple. `Triple` implements +`FromStr` and `fmt::Display` so it can be converted to and from the +conventional string representation of a triple. + +`Triple` also has functions for querying a triple's endianness, +pointer bit width, and binary format. + +And, `Triple` and the enum types have `host()` constructors, for targeting +the host. + +It supports all triples currently used by rustc and rustup. + +It does not support reading JSON target files itself. To use it with a JSON +target file, construct a `Triple` using the value of the "llvm-target" field. diff --git a/third_party/rust/target-lexicon/build.rs b/third_party/rust/target-lexicon/build.rs new file mode 100644 index 0000000000..464554e854 --- /dev/null +++ b/third_party/rust/target-lexicon/build.rs @@ -0,0 +1,191 @@ +//! build.rs file to obtain the host information. + +// Allow dead code in triple.rs and targets.rs for our purposes here. +#![allow(dead_code)] + +use std::env; +use std::fs::File; +use std::io::{self, Write}; +use std::path::PathBuf; +use std::str::FromStr; + +extern crate alloc; + +// Include triple.rs and targets.rs so we can parse the TARGET environment variable. +// targets.rs depends on data_model +mod data_model { + include!("src/data_model.rs"); +} +mod triple { + include!("src/triple.rs"); +} +mod targets { + include!("src/targets.rs"); +} + +// Stub out `ParseError` to minimally support triple.rs and targets.rs. +mod parse_error { + #[derive(Debug)] + pub enum ParseError { + UnrecognizedArchitecture(String), + UnrecognizedVendor(String), + UnrecognizedOperatingSystem(String), + UnrecognizedEnvironment(String), + UnrecognizedBinaryFormat(String), + UnrecognizedField(String), + } +} + +use self::targets::Vendor; +use self::triple::Triple; + +fn main() { + let out_dir = + PathBuf::from(env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set")); + let target = env::var("TARGET").expect("The TARGET environment variable must be set"); + let triple = + Triple::from_str(&target).unwrap_or_else(|_| panic!("Invalid target name: '{}'", target)); + let out = File::create(out_dir.join("host.rs")).expect("error creating host.rs"); + write_host_rs(out, triple).expect("error writing host.rs"); +} + +fn write_host_rs(mut out: File, triple: Triple) -> io::Result<()> { + // The generated Debug implementation for the inner architecture variants + // doesn't print the enum name qualifier, so import them here. There + // shouldn't be any conflicts because these enums all share a namespace + // in the triple string format. + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::Aarch64Architecture::*;")?; + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::ArmArchitecture::*;")?; + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::X86_32Architecture::*;")?; + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::Mips32Architecture::*;")?; + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::Mips64Architecture::*;")?; + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::Riscv32Architecture::*;")?; + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::Riscv64Architecture::*;")?; + writeln!(out, "#[allow(unused_imports)]")?; + writeln!(out, "use crate::CustomVendor;")?; + writeln!(out)?; + writeln!(out, "/// The `Triple` of the current host.")?; + writeln!(out, "pub const HOST: Triple = Triple {{")?; + writeln!( + out, + " architecture: Architecture::{:?},", + triple.architecture + )?; + writeln!( + out, + " vendor: Vendor::{},", + vendor_display(&triple.vendor) + )?; + writeln!( + out, + " operating_system: OperatingSystem::{:?},", + triple.operating_system + )?; + writeln!( + out, + " environment: Environment::{:?},", + triple.environment + )?; + writeln!( + out, + " binary_format: BinaryFormat::{:?},", + triple.binary_format + )?; + writeln!(out, "}};")?; + writeln!(out)?; + + writeln!(out, "impl Architecture {{")?; + writeln!(out, " /// Return the architecture for the current host.")?; + writeln!(out, " pub const fn host() -> Self {{")?; + writeln!(out, " Self::{:?}", triple.architecture)?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl Vendor {{")?; + writeln!(out, " /// Return the vendor for the current host.")?; + writeln!(out, " pub const fn host() -> Self {{")?; + writeln!(out, " Self::{}", vendor_display(&triple.vendor))?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl OperatingSystem {{")?; + writeln!( + out, + " /// Return the operating system for the current host." + )?; + writeln!(out, " pub const fn host() -> Self {{")?; + writeln!(out, " Self::{:?}", triple.operating_system)?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl Environment {{")?; + writeln!(out, " /// Return the environment for the current host.")?; + writeln!(out, " pub const fn host() -> Self {{")?; + writeln!(out, " Self::{:?}", triple.environment)?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl BinaryFormat {{")?; + writeln!( + out, + " /// Return the binary format for the current host." + )?; + writeln!(out, " pub const fn host() -> Self {{")?; + writeln!(out, " Self::{:?}", triple.binary_format)?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + writeln!(out)?; + + writeln!(out, "impl Triple {{")?; + writeln!(out, " /// Return the triple for the current host.")?; + writeln!(out, " pub const fn host() -> Self {{")?; + writeln!(out, " Self {{")?; + writeln!( + out, + " architecture: Architecture::{:?},", + triple.architecture + )?; + writeln!( + out, + " vendor: Vendor::{},", + vendor_display(&triple.vendor) + )?; + writeln!( + out, + " operating_system: OperatingSystem::{:?},", + triple.operating_system + )?; + writeln!( + out, + " environment: Environment::{:?},", + triple.environment + )?; + writeln!( + out, + " binary_format: BinaryFormat::{:?},", + triple.binary_format + )?; + writeln!(out, " }}")?; + writeln!(out, " }}")?; + writeln!(out, "}}")?; + + Ok(()) +} + +fn vendor_display(vendor: &Vendor) -> String { + match vendor { + Vendor::Custom(custom) => format!("CustomVendor::Static({:?})", custom.as_str()), + known => format!("{:?}", known), + } +} diff --git a/third_party/rust/target-lexicon/examples/host.rs b/third_party/rust/target-lexicon/examples/host.rs new file mode 100644 index 0000000000..055e0bffdb --- /dev/null +++ b/third_party/rust/target-lexicon/examples/host.rs @@ -0,0 +1,12 @@ +extern crate target_lexicon; + +use target_lexicon::HOST; + +fn main() { + println!( + "{}", + HOST.pointer_width() + .expect("architecture should be known") + .bytes() + ); +} diff --git a/third_party/rust/target-lexicon/examples/misc.rs b/third_party/rust/target-lexicon/examples/misc.rs new file mode 100644 index 0000000000..25c99e8677 --- /dev/null +++ b/third_party/rust/target-lexicon/examples/misc.rs @@ -0,0 +1,14 @@ +extern crate target_lexicon; + +use core::str::FromStr; +use target_lexicon::{Triple, HOST}; + +fn main() { + println!("The host triple is {}.", HOST); + + let e = Triple::from_str("riscv32-unknown-unknown") + .expect("expected to recognize the RISC-V target") + .endianness() + .expect("expected to know the endianness of RISC-V"); + println!("The endianness of RISC-V is {:?}.", e); +} diff --git a/third_party/rust/target-lexicon/scripts/rust-targets.sh b/third_party/rust/target-lexicon/scripts/rust-targets.sh new file mode 100755 index 0000000000..922950d0a0 --- /dev/null +++ b/third_party/rust/target-lexicon/scripts/rust-targets.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail + +rustup target list | sed 's/ (.*//' > list.txt +rustc +nightly --print target-list >> list.txt +cat list.txt | sort | uniq |sed 's/\(.*\)/ "\1",/' > sorted.txt +rm list.txt diff --git a/third_party/rust/target-lexicon/src/data_model.rs b/third_party/rust/target-lexicon/src/data_model.rs new file mode 100644 index 0000000000..738f2f6856 --- /dev/null +++ b/third_party/rust/target-lexicon/src/data_model.rs @@ -0,0 +1,105 @@ +/// The size of a type. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Size { + U8, + U16, + U32, + U64, +} + +impl Size { + /// Return the number of bits this `Size` represents. + pub fn bits(self) -> u8 { + match self { + Self::U8 => 8, + Self::U16 => 16, + Self::U32 => 32, + Self::U64 => 64, + } + } + + /// Return the number of bytes in a size. + /// + /// A byte is assumed to be 8 bits. + pub fn bytes(self) -> u8 { + match self { + Self::U8 => 1, + Self::U16 => 2, + Self::U32 => 4, + Self::U64 => 8, + } + } +} + +/// The C data model used on a target. +/// +/// See also https://en.cppreference.com/w/c/language/arithmetic_types +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum CDataModel { + /// The data model used most commonly on Win16. `long` and `pointer` are 32 bits. + LP32, + /// The data model used most commonly on Win32 and 32-bit Unix systems. + /// + /// `int`, `long`, and `pointer` are all 32 bits. + ILP32, + /// The data model used most commonly on Win64 + /// + /// `long long`, and `pointer` are 64 bits. + LLP64, + /// The data model used most commonly on 64-bit Unix systems + /// + /// `long`, and `pointer` are 64 bits. + LP64, + /// A rare data model used on early 64-bit Unix systems + /// + /// `int`, `long`, and `pointer` are all 64 bits. + ILP64, +} + +impl CDataModel { + /// The width of a pointer (in the default address space). + pub fn pointer_width(self) -> Size { + match self { + Self::LP32 | Self::ILP32 => Size::U32, + Self::LLP64 | Self::LP64 | Self::ILP64 => Size::U64, + } + } + /// The size of a C `short`. This is required to be at least 16 bits. + pub fn short_size(self) -> Size { + match self { + Self::LP32 | Self::ILP32 | Self::LLP64 | Self::LP64 | Self::ILP64 => Size::U16, + } + } + /// The size of a C `int`. This is required to be at least 16 bits. + pub fn int_size(self) -> Size { + match self { + Self::LP32 => Size::U16, + Self::ILP32 | Self::LLP64 | Self::LP64 | Self::ILP64 => Size::U32, + } + } + /// The size of a C `long`. This is required to be at least 32 bits. + pub fn long_size(self) -> Size { + match self { + Self::LP32 | Self::ILP32 | Self::LLP64 | Self::ILP64 => Size::U32, + Self::LP64 => Size::U64, + } + } + /// The size of a C `long long`. This is required (in C99+) to be at least 64 bits. + pub fn long_long_size(self) -> Size { + match self { + Self::LP32 | Self::ILP32 | Self::LLP64 | Self::ILP64 | Self::LP64 => Size::U64, + } + } + /// The size of a C `float`. + pub fn float_size(self) -> Size { + // TODO: this is probably wrong on at least one architecture + Size::U32 + } + /// The size of a C `double`. + pub fn double_size(self) -> Size { + // TODO: this is probably wrong on at least one architecture + Size::U64 + } +} diff --git a/third_party/rust/target-lexicon/src/host.rs b/third_party/rust/target-lexicon/src/host.rs new file mode 100644 index 0000000000..4c6ad5ba54 --- /dev/null +++ b/third_party/rust/target-lexicon/src/host.rs @@ -0,0 +1,56 @@ +use crate::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; + +// Include the implementations of the `HOST` object containing information +// about the current host. +include!(concat!(env!("OUT_DIR"), "/host.rs")); + +#[cfg(test)] +mod tests { + #[cfg(target_os = "linux")] + #[test] + fn test_linux() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Linux); + } + + #[cfg(target_os = "macos")] + #[test] + fn test_macos() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Darwin); + } + + #[cfg(windows)] + #[test] + fn test_windows() { + use super::*; + assert_eq!(OperatingSystem::host(), OperatingSystem::Windows); + } + + #[cfg(target_pointer_width = "16")] + #[test] + fn test_ptr16() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 16); + } + + #[cfg(target_pointer_width = "32")] + #[test] + fn test_ptr32() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 32); + } + + #[cfg(target_pointer_width = "64")] + #[test] + fn test_ptr64() { + use super::*; + assert_eq!(Architecture::host().pointer_width().unwrap().bits(), 64); + } + + #[test] + fn host_object() { + use super::*; + assert_eq!(HOST, Triple::host()); + } +} diff --git a/third_party/rust/target-lexicon/src/lib.rs b/third_party/rust/target-lexicon/src/lib.rs new file mode 100644 index 0000000000..5b48872301 --- /dev/null +++ b/third_party/rust/target-lexicon/src/lib.rs @@ -0,0 +1,57 @@ +//! Target triple support. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![warn(unused_import_braces)] +#![cfg_attr( + feature = "cargo-clippy", + warn( + clippy::float_arithmetic, + clippy::mut_mut, + clippy::nonminimal_bool, + clippy::option_map_unwrap_or, + clippy::option_map_unwrap_or_else, + clippy::print_stdout, + clippy::unicode_not_nfc, + clippy::use_self, + ) +)] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +mod data_model; +mod host; +mod parse_error; +mod targets; +#[macro_use] +mod triple; + +pub use self::data_model::{CDataModel, Size}; +pub use self::host::HOST; +pub use self::parse_error::ParseError; +pub use self::targets::{ + Aarch64Architecture, Architecture, ArmArchitecture, BinaryFormat, CustomVendor, Environment, + Mips32Architecture, Mips64Architecture, OperatingSystem, Riscv32Architecture, + Riscv64Architecture, Vendor, X86_32Architecture, +}; +pub use self::triple::{CallingConvention, Endianness, PointerWidth, Triple}; + +/// A simple wrapper around `Triple` that provides an implementation of +/// `Default` which defaults to `Triple::host()`. +pub struct DefaultToHost(pub Triple); + +impl Default for DefaultToHost { + fn default() -> Self { + Self(Triple::host()) + } +} + +/// A simple wrapper around `Triple` that provides an implementation of +/// `Default` which defaults to `Triple::unknown()`. +pub struct DefaultToUnknown(pub Triple); + +impl Default for DefaultToUnknown { + fn default() -> Self { + Self(Triple::unknown()) + } +} diff --git a/third_party/rust/target-lexicon/src/parse_error.rs b/third_party/rust/target-lexicon/src/parse_error.rs new file mode 100644 index 0000000000..03ca4aedb9 --- /dev/null +++ b/third_party/rust/target-lexicon/src/parse_error.rs @@ -0,0 +1,34 @@ +use alloc::string::String; + +use core::fmt; + +/// An error returned from parsing a triple. +#[derive(Clone, Debug, PartialEq, Eq)] +#[allow(missing_docs)] +pub enum ParseError { + UnrecognizedArchitecture(String), + UnrecognizedVendor(String), + UnrecognizedOperatingSystem(String), + UnrecognizedEnvironment(String), + UnrecognizedBinaryFormat(String), + UnrecognizedField(String), +} + +impl fmt::Display for ParseError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use ParseError::*; + match self { + UnrecognizedArchitecture(msg) => write!(fmt, "Unrecognized architecture: {}", msg), + UnrecognizedVendor(msg) => write!(fmt, "Unrecognized vendor: {}", msg), + UnrecognizedOperatingSystem(msg) => { + write!(fmt, "Unrecognized operating system: {}", msg) + } + UnrecognizedEnvironment(msg) => write!(fmt, "Unrecognized environment: {}", msg), + UnrecognizedBinaryFormat(msg) => write!(fmt, "Unrecognized binary format: {}", msg), + UnrecognizedField(msg) => write!(fmt, "Unrecognized field: {}", msg), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseError {} diff --git a/third_party/rust/target-lexicon/src/targets.rs b/third_party/rust/target-lexicon/src/targets.rs new file mode 100644 index 0000000000..c3d0e68e4d --- /dev/null +++ b/third_party/rust/target-lexicon/src/targets.rs @@ -0,0 +1,1445 @@ +// This file defines all the identifier enums and target-aware logic. + +use crate::triple::{Endianness, PointerWidth, Triple}; +use alloc::boxed::Box; +use alloc::string::String; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::str::FromStr; + +/// The "architecture" field, which in some cases also specifies a specific +/// subarchitecture. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Architecture { + Unknown, + Arm(ArmArchitecture), + AmdGcn, + Aarch64(Aarch64Architecture), + Asmjs, + Hexagon, + X86_32(X86_32Architecture), + Mips32(Mips32Architecture), + Mips64(Mips64Architecture), + Msp430, + Nvptx64, + Powerpc, + Powerpc64, + Powerpc64le, + Riscv32(Riscv32Architecture), + Riscv64(Riscv64Architecture), + S390x, + Sparc, + Sparc64, + Sparcv9, + Wasm32, + Wasm64, + X86_64, +} + +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum ArmArchitecture { + Arm, // Generic arm + Armeb, + Armv4, + Armv4t, + Armv5t, + Armv5te, + Armv5tej, + Armv6, + Armv6j, + Armv6k, + Armv6z, + Armv6kz, + Armv6t2, + Armv6m, + Armv7, + Armv7a, + Armv7ve, + Armv7m, + Armv7r, + Armv7s, + Armv8, + Armv8a, + Armv8_1a, + Armv8_2a, + Armv8_3a, + Armv8_4a, + Armv8_5a, + Armv8mBase, + Armv8mMain, + Armv8r, + + Armebv7r, + + Thumbeb, + Thumbv6m, + Thumbv7a, + Thumbv7em, + Thumbv7m, + Thumbv7neon, + Thumbv8mBase, + Thumbv8mMain, +} + +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Aarch64Architecture { + Aarch64, + Aarch64be, +} + +// #[non_exhaustive] +// #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +// #[allow(missing_docs)] +// pub enum ArmFpu { +// Vfp, +// Vfpv2, +// Vfpv3, +// Vfpv3Fp16, +// Vfpv3Xd, +// Vfpv3XdFp16, +// Neon, +// NeonVfpv3, +// NeonVfpv4, +// Vfpv4, +// Vfpv4D16, +// Fpv4SpD16, +// Fpv5SpD16, +// Fpv5D16, +// FpArmv8, +// NeonFpArmv8, +// CryptoNeonFpArmv8, +// } + +impl ArmArchitecture { + /// Test if this architecture uses the Thumb instruction set. + pub fn is_thumb(self) -> bool { + match self { + Self::Arm + | Self::Armeb + | Self::Armv4 + | Self::Armv4t + | Self::Armv5t + | Self::Armv5te + | Self::Armv5tej + | Self::Armv6 + | Self::Armv6j + | Self::Armv6k + | Self::Armv6z + | Self::Armv6kz + | Self::Armv6t2 + | Self::Armv6m + | Self::Armv7 + | Self::Armv7a + | Self::Armv7ve + | Self::Armv7m + | Self::Armv7r + | Self::Armv7s + | Self::Armv8 + | Self::Armv8a + | Self::Armv8_1a + | Self::Armv8_2a + | Self::Armv8_3a + | Self::Armv8_4a + | Self::Armv8_5a + | Self::Armv8mBase + | Self::Armv8mMain + | Self::Armv8r + | Self::Armebv7r => false, + Self::Thumbeb + | Self::Thumbv6m + | Self::Thumbv7a + | Self::Thumbv7em + | Self::Thumbv7m + | Self::Thumbv7neon + | Self::Thumbv8mBase + | Self::Thumbv8mMain => true, + } + } + + // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> { + + // } + + /// Return the pointer bit width of this target's architecture. + pub fn pointer_width(self) -> PointerWidth { + match self { + Self::Arm + | Self::Armeb + | Self::Armv4 + | Self::Armv4t + | Self::Armv5t + | Self::Armv5te + | Self::Armv5tej + | Self::Armv6 + | Self::Armv6j + | Self::Armv6k + | Self::Armv6z + | Self::Armv6kz + | Self::Armv6t2 + | Self::Armv6m + | Self::Armv7 + | Self::Armv7a + | Self::Armv7ve + | Self::Armv7m + | Self::Armv7r + | Self::Armv7s + | Self::Armv8 + | Self::Armv8a + | Self::Armv8_1a + | Self::Armv8_2a + | Self::Armv8_3a + | Self::Armv8_4a + | Self::Armv8_5a + | Self::Armv8mBase + | Self::Armv8mMain + | Self::Armv8r + | Self::Armebv7r + | Self::Thumbeb + | Self::Thumbv6m + | Self::Thumbv7a + | Self::Thumbv7em + | Self::Thumbv7m + | Self::Thumbv7neon + | Self::Thumbv8mBase + | Self::Thumbv8mMain => PointerWidth::U32, + } + } + + /// Return the endianness of this architecture. + pub fn endianness(self) -> Endianness { + match self { + Self::Arm + | Self::Armv4 + | Self::Armv4t + | Self::Armv5t + | Self::Armv5te + | Self::Armv5tej + | Self::Armv6 + | Self::Armv6j + | Self::Armv6k + | Self::Armv6z + | Self::Armv6kz + | Self::Armv6t2 + | Self::Armv6m + | Self::Armv7 + | Self::Armv7a + | Self::Armv7ve + | Self::Armv7m + | Self::Armv7r + | Self::Armv7s + | Self::Armv8 + | Self::Armv8a + | Self::Armv8_1a + | Self::Armv8_2a + | Self::Armv8_3a + | Self::Armv8_4a + | Self::Armv8_5a + | Self::Armv8mBase + | Self::Armv8mMain + | Self::Armv8r + | Self::Thumbv6m + | Self::Thumbv7a + | Self::Thumbv7em + | Self::Thumbv7m + | Self::Thumbv7neon + | Self::Thumbv8mBase + | Self::Thumbv8mMain => Endianness::Little, + Self::Armeb | Self::Armebv7r | Self::Thumbeb => Endianness::Big, + } + } +} + +impl Aarch64Architecture { + /// Test if this architecture uses the Thumb instruction set. + pub fn is_thumb(self) -> bool { + match self { + Self::Aarch64 | Self::Aarch64be => false, + } + } + + // pub fn has_fpu(self) -> Result<&'static [ArmFpu], ()> { + + // } + + /// Return the pointer bit width of this target's architecture. + pub fn pointer_width(self) -> PointerWidth { + match self { + Self::Aarch64 | Self::Aarch64be => PointerWidth::U64, + } + } + + /// Return the endianness of this architecture. + pub fn endianness(self) -> Endianness { + match self { + Self::Aarch64 => Endianness::Little, + Self::Aarch64be => Endianness::Big, + } + } +} + +/// An enum for all 32-bit RISC-V architectures. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Riscv32Architecture { + Riscv32, + Riscv32i, + Riscv32imac, + Riscv32imc, +} + +/// An enum for all 64-bit RISC-V architectures. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Riscv64Architecture { + Riscv64, + Riscv64gc, + Riscv64imac, +} + +/// An enum for all 32-bit x86 architectures. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum X86_32Architecture { + I386, + I586, + I686, +} + +/// An enum for all 32-bit MIPS architectures (not just "MIPS32"). +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Mips32Architecture { + Mips, + Mipsel, + Mipsisa32r6, + Mipsisa32r6el, +} + +/// An enum for all 64-bit MIPS architectures (not just "MIPS64"). +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Mips64Architecture { + Mips64, + Mips64el, + Mipsisa64r6, + Mipsisa64r6el, +} + +/// A string for a `Vendor::Custom` that can either be used in `const` +/// contexts or hold dynamic strings. +#[derive(Clone, Debug, Eq)] +pub enum CustomVendor { + /// An owned `String`. This supports the general case. + Owned(Box<String>), + /// A static `str`, so that `CustomVendor` can be constructed in `const` + /// contexts. + Static(&'static str), +} + +impl CustomVendor { + /// Extracts a string slice. + pub fn as_str(&self) -> &str { + match self { + Self::Owned(s) => s, + Self::Static(s) => s, + } + } +} + +impl PartialEq for CustomVendor { + fn eq(&self, other: &Self) -> bool { + self.as_str() == other.as_str() + } +} + +impl Hash for CustomVendor { + fn hash<H: Hasher>(&self, state: &mut H) { + self.as_str().hash(state) + } +} + +/// The "vendor" field, which in practice is little more than an arbitrary +/// modifier. +#[non_exhaustive] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Vendor { + Unknown, + Amd, + Apple, + Experimental, + Fortanix, + Nvidia, + Pc, + Rumprun, + Sun, + Uwp, + Wrs, + + /// A custom vendor. "Custom" in this context means that the vendor is + /// not specifically recognized by upstream Autotools, LLVM, Rust, or other + /// relevant authorities on triple naming. It's useful for people building + /// and using locally patched toolchains. + /// + /// Outside of such patched environments, users of `target-lexicon` should + /// treat `Custom` the same as `Unknown` and ignore the string. + Custom(CustomVendor), +} + +/// The "operating system" field, which sometimes implies an environment, and +/// sometimes isn't an actual operating system. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum OperatingSystem { + Unknown, + AmdHsa, + Bitrig, + Cloudabi, + Cuda, + Darwin, + Dragonfly, + Emscripten, + Freebsd, + Fuchsia, + Haiku, + Hermit, + Illumos, + Ios, + L4re, + Linux, + MacOSX { major: u16, minor: u16, patch: u16 }, + Nebulet, + Netbsd, + None_, + Openbsd, + Psp, + Redox, + Solaris, + Uefi, + VxWorks, + Wasi, + Windows, +} + +/// The "environment" field, which specifies an ABI environment on top of the +/// operating system. In many configurations, this field is omitted, and the +/// environment is implied by the operating system. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Environment { + Unknown, + AmdGiz, + Android, + Androideabi, + Eabi, + Eabihf, + Gnu, + Gnuabi64, + Gnueabi, + Gnueabihf, + Gnuspe, + Gnux32, + Macabi, + Musl, + Musleabi, + Musleabihf, + Muslabi64, + Msvc, + Kernel, + Uclibc, + Sgx, + Softfloat, + Spe, +} + +/// The "binary format" field, which is usually omitted, and the binary format +/// is implied by the other fields. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum BinaryFormat { + Unknown, + Elf, + Coff, + Macho, + Wasm, +} + +impl Architecture { + /// Return the endianness of this architecture. + pub fn endianness(self) -> Result<Endianness, ()> { + match self { + Self::Unknown => Err(()), + Self::Arm(arm) => Ok(arm.endianness()), + Self::Aarch64(aarch) => Ok(aarch.endianness()), + Self::AmdGcn + | Self::Asmjs + | Self::Hexagon + | Self::X86_32(_) + | Self::Mips64(Mips64Architecture::Mips64el) + | Self::Mips32(Mips32Architecture::Mipsel) + | Self::Mips32(Mips32Architecture::Mipsisa32r6el) + | Self::Mips64(Mips64Architecture::Mipsisa64r6el) + | Self::Msp430 + | Self::Nvptx64 + | Self::Powerpc64le + | Self::Riscv32(_) + | Self::Riscv64(_) + | Self::Wasm32 + | Self::Wasm64 + | Self::X86_64 => Ok(Endianness::Little), + Self::Mips32(Mips32Architecture::Mips) + | Self::Mips64(Mips64Architecture::Mips64) + | Self::Mips32(Mips32Architecture::Mipsisa32r6) + | Self::Mips64(Mips64Architecture::Mipsisa64r6) + | Self::Powerpc + | Self::Powerpc64 + | Self::S390x + | Self::Sparc + | Self::Sparc64 + | Self::Sparcv9 => Ok(Endianness::Big), + } + } + + /// Return the pointer bit width of this target's architecture. + pub fn pointer_width(self) -> Result<PointerWidth, ()> { + match self { + Self::Unknown => Err(()), + Self::Msp430 => Ok(PointerWidth::U16), + Self::Arm(arm) => Ok(arm.pointer_width()), + Self::Aarch64(aarch) => Ok(aarch.pointer_width()), + Self::Asmjs + | Self::Hexagon + | Self::X86_32(_) + | Self::Riscv32(_) + | Self::Sparc + | Self::Wasm32 + | Self::Mips32(_) + | Self::Powerpc => Ok(PointerWidth::U32), + Self::AmdGcn + | Self::Powerpc64le + | Self::Riscv64(_) + | Self::X86_64 + | Self::Mips64(_) + | Self::Nvptx64 + | Self::Powerpc64 + | Self::S390x + | Self::Sparc64 + | Self::Sparcv9 + | Self::Wasm64 => Ok(PointerWidth::U64), + } + } +} + +/// Return the binary format implied by this target triple, ignoring its +/// `binary_format` field. +pub(crate) fn default_binary_format(triple: &Triple) -> BinaryFormat { + match triple.operating_system { + OperatingSystem::None_ => match triple.environment { + Environment::Eabi | Environment::Eabihf => BinaryFormat::Elf, + _ => BinaryFormat::Unknown, + }, + OperatingSystem::Darwin | OperatingSystem::Ios | OperatingSystem::MacOSX { .. } => { + BinaryFormat::Macho + } + OperatingSystem::Windows => BinaryFormat::Coff, + OperatingSystem::Nebulet + | OperatingSystem::Emscripten + | OperatingSystem::VxWorks + | OperatingSystem::Wasi + | OperatingSystem::Unknown => match triple.architecture { + Architecture::Wasm32 | Architecture::Wasm64 => BinaryFormat::Wasm, + _ => BinaryFormat::Unknown, + }, + _ => BinaryFormat::Elf, + } +} + +impl fmt::Display for ArmArchitecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Arm => "arm", + Self::Armeb => "armeb", + Self::Armv4 => "armv4", + Self::Armv4t => "armv4t", + Self::Armv5t => "armv5t", + Self::Armv5te => "armv5te", + Self::Armv5tej => "armv5tej", + Self::Armv6 => "armv6", + Self::Armv6j => "armv6j", + Self::Armv6k => "armv6k", + Self::Armv6z => "armv6z", + Self::Armv6kz => "armv6kz", + Self::Armv6t2 => "armv6t2", + Self::Armv6m => "armv6m", + Self::Armv7 => "armv7", + Self::Armv7a => "armv7a", + Self::Armv7ve => "armv7ve", + Self::Armv7m => "armv7m", + Self::Armv7r => "armv7r", + Self::Armv7s => "armv7s", + Self::Armv8 => "armv8", + Self::Armv8a => "armv8a", + Self::Armv8_1a => "armv8.1a", + Self::Armv8_2a => "armv8.2a", + Self::Armv8_3a => "armv8.3a", + Self::Armv8_4a => "armv8.4a", + Self::Armv8_5a => "armv8.5a", + Self::Armv8mBase => "armv8m.base", + Self::Armv8mMain => "armv8m.main", + Self::Armv8r => "armv8r", + Self::Thumbeb => "thumbeb", + Self::Thumbv6m => "thumbv6m", + Self::Thumbv7a => "thumbv7a", + Self::Thumbv7em => "thumbv7em", + Self::Thumbv7m => "thumbv7m", + Self::Thumbv7neon => "thumbv7neon", + Self::Thumbv8mBase => "thumbv8m.base", + Self::Thumbv8mMain => "thumbv8m.main", + Self::Armebv7r => "armebv7r", + }; + f.write_str(s) + } +} + +impl fmt::Display for Aarch64Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Aarch64 => "aarch64", + Self::Aarch64be => "aarch64be", + }; + f.write_str(s) + } +} + +impl fmt::Display for Riscv32Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Riscv32 => "riscv32", + Self::Riscv32i => "riscv32i", + Self::Riscv32imac => "riscv32imac", + Self::Riscv32imc => "riscv32imc", + }; + f.write_str(s) + } +} + +impl fmt::Display for Riscv64Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Riscv64 => "riscv64", + Self::Riscv64gc => "riscv64gc", + Self::Riscv64imac => "riscv64imac", + }; + f.write_str(s) + } +} + +impl fmt::Display for X86_32Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::I386 => "i386", + Self::I586 => "i586", + Self::I686 => "i686", + }; + f.write_str(s) + } +} + +impl fmt::Display for Mips32Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Mips => "mips", + Self::Mipsel => "mipsel", + Self::Mipsisa32r6 => "mipsisa32r6", + Self::Mipsisa32r6el => "mipsisa32r6el", + }; + f.write_str(s) + } +} + +impl fmt::Display for Mips64Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Mips64 => "mips64", + Self::Mips64el => "mips64el", + Self::Mipsisa64r6 => "mipsisa64r6", + Self::Mipsisa64r6el => "mipsisa64r6el", + }; + f.write_str(s) + } +} + +impl fmt::Display for Architecture { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Arm(arm) => arm.fmt(f), + Self::Aarch64(aarch) => aarch.fmt(f), + Self::Unknown => f.write_str("unknown"), + Self::AmdGcn => f.write_str("amdgcn"), + Self::Asmjs => f.write_str("asmjs"), + Self::Hexagon => f.write_str("hexagon"), + Self::X86_32(x86_32) => x86_32.fmt(f), + Self::Mips32(mips32) => mips32.fmt(f), + Self::Mips64(mips64) => mips64.fmt(f), + Self::Msp430 => f.write_str("msp430"), + Self::Nvptx64 => f.write_str("nvptx64"), + Self::Powerpc => f.write_str("powerpc"), + Self::Powerpc64 => f.write_str("powerpc64"), + Self::Powerpc64le => f.write_str("powerpc64le"), + Self::Riscv32(riscv32) => riscv32.fmt(f), + Self::Riscv64(riscv64) => riscv64.fmt(f), + Self::S390x => f.write_str("s390x"), + Self::Sparc => f.write_str("sparc"), + Self::Sparc64 => f.write_str("sparc64"), + Self::Sparcv9 => f.write_str("sparcv9"), + Self::Wasm32 => f.write_str("wasm32"), + Self::Wasm64 => f.write_str("wasm64"), + Self::X86_64 => f.write_str("x86_64"), + } + } +} + +impl FromStr for ArmArchitecture { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "arm" => Self::Arm, + "armeb" => Self::Armeb, + "armv4" => Self::Armv4, + "armv4t" => Self::Armv4t, + "armv5t" => Self::Armv5t, + "armv5te" => Self::Armv5te, + "armv5tej" => Self::Armv5tej, + "armv6" => Self::Armv6, + "armv6j" => Self::Armv6j, + "armv6k" => Self::Armv6k, + "armv6z" => Self::Armv6z, + "armv6kz" => Self::Armv6kz, + "armv6t2" => Self::Armv6t2, + "armv6m" => Self::Armv6m, + "armv7" => Self::Armv7, + "armv7a" => Self::Armv7a, + "armv7ve" => Self::Armv7ve, + "armv7m" => Self::Armv7m, + "armv7r" => Self::Armv7r, + "armv7s" => Self::Armv7s, + "armv8" => Self::Armv8, + "armv8a" => Self::Armv8a, + "armv8.1a" => Self::Armv8_1a, + "armv8.2a" => Self::Armv8_2a, + "armv8.3a" => Self::Armv8_3a, + "armv8.4a" => Self::Armv8_4a, + "armv8.5a" => Self::Armv8_5a, + "armv8m.base" => Self::Armv8mBase, + "armv8m.main" => Self::Armv8mMain, + "armv8r" => Self::Armv8r, + "thumbeb" => Self::Thumbeb, + "thumbv6m" => Self::Thumbv6m, + "thumbv7a" => Self::Thumbv7a, + "thumbv7em" => Self::Thumbv7em, + "thumbv7m" => Self::Thumbv7m, + "thumbv7neon" => Self::Thumbv7neon, + "thumbv8m.base" => Self::Thumbv8mBase, + "thumbv8m.main" => Self::Thumbv8mMain, + "armebv7r" => Self::Armebv7r, + _ => return Err(()), + }) + } +} + +impl FromStr for Aarch64Architecture { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "aarch64" => Self::Aarch64, + "arm64" => Self::Aarch64, + "aarch64be" => Self::Aarch64be, + _ => return Err(()), + }) + } +} + +impl FromStr for Riscv32Architecture { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "riscv32" => Self::Riscv32, + "riscv32i" => Self::Riscv32i, + "riscv32imac" => Self::Riscv32imac, + "riscv32imc" => Self::Riscv32imc, + _ => return Err(()), + }) + } +} + +impl FromStr for Riscv64Architecture { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "riscv64" => Self::Riscv64, + "riscv64gc" => Self::Riscv64gc, + "riscv64imac" => Self::Riscv64imac, + _ => return Err(()), + }) + } +} + +impl FromStr for X86_32Architecture { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "i386" => Self::I386, + "i586" => Self::I586, + "i686" => Self::I686, + _ => return Err(()), + }) + } +} + +impl FromStr for Mips32Architecture { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "mips" => Self::Mips, + "mipsel" => Self::Mipsel, + "mipsisa32r6" => Self::Mipsisa32r6, + "mipsisa32r6el" => Self::Mipsisa32r6el, + _ => return Err(()), + }) + } +} + +impl FromStr for Mips64Architecture { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "mips64" => Self::Mips64, + "mips64el" => Self::Mips64el, + "mipsisa64r6" => Self::Mipsisa64r6, + "mipsisa64r6el" => Self::Mipsisa64r6el, + _ => return Err(()), + }) + } +} + +impl FromStr for Architecture { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "unknown" => Self::Unknown, + "amdgcn" => Self::AmdGcn, + "asmjs" => Self::Asmjs, + "hexagon" => Self::Hexagon, + "msp430" => Self::Msp430, + "nvptx64" => Self::Nvptx64, + "powerpc" => Self::Powerpc, + "powerpc64" => Self::Powerpc64, + "powerpc64le" => Self::Powerpc64le, + "s390x" => Self::S390x, + "sparc" => Self::Sparc, + "sparc64" => Self::Sparc64, + "sparcv9" => Self::Sparcv9, + "wasm32" => Self::Wasm32, + "wasm64" => Self::Wasm64, + "x86_64" => Self::X86_64, + _ => { + if let Ok(arm) = ArmArchitecture::from_str(s) { + Self::Arm(arm) + } else if let Ok(aarch64) = Aarch64Architecture::from_str(s) { + Self::Aarch64(aarch64) + } else if let Ok(riscv32) = Riscv32Architecture::from_str(s) { + Self::Riscv32(riscv32) + } else if let Ok(riscv64) = Riscv64Architecture::from_str(s) { + Self::Riscv64(riscv64) + } else if let Ok(x86_32) = X86_32Architecture::from_str(s) { + Self::X86_32(x86_32) + } else if let Ok(mips32) = Mips32Architecture::from_str(s) { + Self::Mips32(mips32) + } else if let Ok(mips64) = Mips64Architecture::from_str(s) { + Self::Mips64(mips64) + } else { + return Err(()); + } + } + }) + } +} + +impl fmt::Display for Vendor { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Unknown => "unknown", + Self::Amd => "amd", + Self::Apple => "apple", + Self::Experimental => "experimental", + Self::Fortanix => "fortanix", + Self::Nvidia => "nvidia", + Self::Pc => "pc", + Self::Rumprun => "rumprun", + Self::Sun => "sun", + Self::Uwp => "uwp", + Self::Wrs => "wrs", + Self::Custom(ref name) => name.as_str(), + }; + f.write_str(s) + } +} + +impl FromStr for Vendor { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "unknown" => Self::Unknown, + "amd" => Self::Amd, + "apple" => Self::Apple, + "experimental" => Self::Experimental, + "fortanix" => Self::Fortanix, + "nvidia" => Self::Nvidia, + "pc" => Self::Pc, + "rumprun" => Self::Rumprun, + "sun" => Self::Sun, + "uwp" => Self::Uwp, + "wrs" => Self::Wrs, + custom => { + use alloc::borrow::ToOwned; + + // A custom vendor. Since triple syntax is so loosely defined, + // be as conservative as we can to avoid potential ambiguities. + // We err on the side of being too strict here, as we can + // always relax it if needed. + + // Don't allow empty string names. + if custom.is_empty() { + return Err(()); + } + + // Don't allow any other recognized name as a custom vendor, + // since vendors can be omitted in some contexts. + if Architecture::from_str(custom).is_ok() + || OperatingSystem::from_str(custom).is_ok() + || Environment::from_str(custom).is_ok() + || BinaryFormat::from_str(custom).is_ok() + { + return Err(()); + } + + // Require the first character to be an ascii lowercase. + if !custom.chars().next().unwrap().is_ascii_lowercase() { + return Err(()); + } + + // Restrict the set of characters permitted in a custom vendor. + let has_restricted = custom.chars().any(|c: char| { + !(c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_' || c == '.') + }); + + if has_restricted { + return Err(()); + } + + Self::Custom(CustomVendor::Owned(Box::new(custom.to_owned()))) + } + }) + } +} + +impl fmt::Display for OperatingSystem { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Unknown => "unknown", + Self::AmdHsa => "amdhsa", + Self::Bitrig => "bitrig", + Self::Cloudabi => "cloudabi", + Self::Cuda => "cuda", + Self::Darwin => "darwin", + Self::Dragonfly => "dragonfly", + Self::Emscripten => "emscripten", + Self::Freebsd => "freebsd", + Self::Fuchsia => "fuchsia", + Self::Haiku => "haiku", + Self::Hermit => "hermit", + Self::Illumos => "illumos", + Self::Ios => "ios", + Self::L4re => "l4re", + Self::Linux => "linux", + Self::MacOSX { + major, + minor, + patch, + } => { + return write!(f, "macosx{}.{}.{}", major, minor, patch); + } + Self::Nebulet => "nebulet", + Self::Netbsd => "netbsd", + Self::None_ => "none", + Self::Openbsd => "openbsd", + Self::Psp => "psp", + Self::Redox => "redox", + Self::Solaris => "solaris", + Self::Uefi => "uefi", + Self::VxWorks => "vxworks", + Self::Wasi => "wasi", + Self::Windows => "windows", + }; + f.write_str(s) + } +} + +impl FromStr for OperatingSystem { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + // TODO also parse version number for darwin and ios OSes + if s.starts_with("macosx") { + // Parse operating system names like `macosx10.7.0`. + let s = &s["macosx".len()..]; + let mut parts = s.split('.').map(|num| num.parse::<u16>()); + + macro_rules! get_part { + () => { + if let Some(Ok(part)) = parts.next() { + part + } else { + return Err(()); + } + }; + } + + let major = get_part!(); + let minor = get_part!(); + let patch = get_part!(); + + if parts.next().is_some() { + return Err(()); + } + + return Ok(Self::MacOSX { + major, + minor, + patch, + }); + } + + Ok(match s { + "unknown" => Self::Unknown, + "amdhsa" => Self::AmdHsa, + "bitrig" => Self::Bitrig, + "cloudabi" => Self::Cloudabi, + "cuda" => Self::Cuda, + "darwin" => Self::Darwin, + "dragonfly" => Self::Dragonfly, + "emscripten" => Self::Emscripten, + "freebsd" => Self::Freebsd, + "fuchsia" => Self::Fuchsia, + "haiku" => Self::Haiku, + "hermit" => Self::Hermit, + "illumos" => Self::Illumos, + "ios" => Self::Ios, + "l4re" => Self::L4re, + "linux" => Self::Linux, + "nebulet" => Self::Nebulet, + "netbsd" => Self::Netbsd, + "none" => Self::None_, + "openbsd" => Self::Openbsd, + "psp" => Self::Psp, + "redox" => Self::Redox, + "solaris" => Self::Solaris, + "uefi" => Self::Uefi, + "vxworks" => Self::VxWorks, + "wasi" => Self::Wasi, + "windows" => Self::Windows, + _ => return Err(()), + }) + } +} + +impl fmt::Display for Environment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Unknown => "unknown", + Self::AmdGiz => "amdgiz", + Self::Android => "android", + Self::Androideabi => "androideabi", + Self::Eabi => "eabi", + Self::Eabihf => "eabihf", + Self::Gnu => "gnu", + Self::Gnuabi64 => "gnuabi64", + Self::Gnueabi => "gnueabi", + Self::Gnueabihf => "gnueabihf", + Self::Gnuspe => "gnuspe", + Self::Gnux32 => "gnux32", + Self::Macabi => "macabi", + Self::Musl => "musl", + Self::Musleabi => "musleabi", + Self::Musleabihf => "musleabihf", + Self::Muslabi64 => "muslabi64", + Self::Msvc => "msvc", + Self::Kernel => "kernel", + Self::Uclibc => "uclibc", + Self::Sgx => "sgx", + Self::Softfloat => "softfloat", + Self::Spe => "spe", + }; + f.write_str(s) + } +} + +impl FromStr for Environment { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "unknown" => Self::Unknown, + "amdgiz" => Self::AmdGiz, + "android" => Self::Android, + "androideabi" => Self::Androideabi, + "eabi" => Self::Eabi, + "eabihf" => Self::Eabihf, + "gnu" => Self::Gnu, + "gnuabi64" => Self::Gnuabi64, + "gnueabi" => Self::Gnueabi, + "gnueabihf" => Self::Gnueabihf, + "gnuspe" => Self::Gnuspe, + "gnux32" => Self::Gnux32, + "macabi" => Self::Macabi, + "musl" => Self::Musl, + "musleabi" => Self::Musleabi, + "musleabihf" => Self::Musleabihf, + "muslabi64" => Self::Muslabi64, + "msvc" => Self::Msvc, + "kernel" => Self::Kernel, + "uclibc" => Self::Uclibc, + "sgx" => Self::Sgx, + "softfloat" => Self::Softfloat, + "spe" => Self::Spe, + _ => return Err(()), + }) + } +} + +impl fmt::Display for BinaryFormat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match *self { + Self::Unknown => "unknown", + Self::Elf => "elf", + Self::Coff => "coff", + Self::Macho => "macho", + Self::Wasm => "wasm", + }; + f.write_str(s) + } +} + +impl FromStr for BinaryFormat { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "unknown" => Self::Unknown, + "elf" => Self::Elf, + "coff" => Self::Coff, + "macho" => Self::Macho, + "wasm" => Self::Wasm, + _ => return Err(()), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::string::ToString; + + #[test] + fn roundtrip_known_triples() { + // This list is constructed from: + // - targets emitted by "rustup target list" + // - targets emitted by "rustc +nightly --print target-list" + // - targets contributors have added + let targets = [ + "aarch64-apple-ios", + "aarch64-fuchsia", + "aarch64-linux-android", + "aarch64-pc-windows-msvc", + "aarch64-unknown-cloudabi", + "aarch64-unknown-freebsd", + "aarch64-unknown-hermit", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", + "aarch64-unknown-netbsd", + "aarch64-unknown-none", + "aarch64-unknown-none-softfloat", + "aarch64-unknown-openbsd", + "aarch64-unknown-redox", + "aarch64-uwp-windows-msvc", + "aarch64-wrs-vxworks", + "amdgcn-amd-amdhsa", + "amdgcn-amd-amdhsa-amdgiz", + "armebv7r-none-eabi", + "armebv7r-none-eabihf", + "arm-linux-androideabi", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "arm-unknown-linux-musleabi", + "arm-unknown-linux-musleabihf", + "armv4t-unknown-linux-gnueabi", + "armv5te-unknown-linux-gnueabi", + "armv5te-unknown-linux-musleabi", + "armv6-unknown-freebsd", + "armv6-unknown-netbsd-eabihf", + "armv7a-none-eabi", + "armv7a-none-eabihf", + "armv7-apple-ios", + "armv7-linux-androideabi", + "armv7r-none-eabi", + "armv7r-none-eabihf", + "armv7s-apple-ios", + "armv7-unknown-cloudabi-eabihf", + "armv7-unknown-freebsd", + "armv7-unknown-linux-gnueabi", + "armv7-unknown-linux-gnueabihf", + "armv7-unknown-linux-musleabi", + "armv7-unknown-linux-musleabihf", + "armv7-unknown-netbsd-eabihf", + "armv7-wrs-vxworks-eabihf", + "asmjs-unknown-emscripten", + "hexagon-unknown-linux-musl", + "i386-apple-ios", + "i586-pc-windows-msvc", + "i586-unknown-linux-gnu", + "i586-unknown-linux-musl", + "i686-apple-darwin", + "i686-linux-android", + "i686-apple-macosx10.7.0", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-cloudabi", + "i686-unknown-dragonfly", + "i686-unknown-freebsd", + "i686-unknown-haiku", + "i686-unknown-linux-gnu", + "i686-unknown-linux-musl", + "i686-unknown-netbsd", + "i686-unknown-openbsd", + "i686-unknown-uefi", + "i686-uwp-windows-gnu", + "i686-uwp-windows-msvc", + "i686-wrs-vxworks", + "mips64el-unknown-linux-gnuabi64", + "mips64el-unknown-linux-muslabi64", + "mips64-unknown-linux-gnuabi64", + "mips64-unknown-linux-muslabi64", + "mipsel-sony-psp", + "mipsel-unknown-linux-gnu", + "mipsel-unknown-linux-musl", + "mipsel-unknown-linux-uclibc", + "mipsisa32r6el-unknown-linux-gnu", + "mipsisa32r6-unknown-linux-gnu", + "mipsisa64r6el-unknown-linux-gnuabi64", + "mipsisa64r6-unknown-linux-gnuabi64", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips-unknown-linux-uclibc", + "msp430-none-elf", + "nvptx64-nvidia-cuda", + "powerpc64le-unknown-linux-gnu", + "powerpc64le-unknown-linux-musl", + "powerpc64-unknown-freebsd", + "powerpc64-unknown-linux-gnu", + "powerpc64-unknown-linux-musl", + "powerpc64-wrs-vxworks", + "powerpc-unknown-linux-gnu", + "powerpc-unknown-linux-gnuspe", + "powerpc-unknown-linux-musl", + "powerpc-unknown-netbsd", + "powerpc-wrs-vxworks", + "powerpc-wrs-vxworks-spe", + "riscv32imac-unknown-none-elf", + "riscv32imc-unknown-none-elf", + "riscv32i-unknown-none-elf", + "riscv64gc-unknown-linux-gnu", + "riscv64gc-unknown-none-elf", + "riscv64imac-unknown-none-elf", + "s390x-unknown-linux-gnu", + "sparc64-unknown-linux-gnu", + "sparc64-unknown-netbsd", + "sparc64-unknown-openbsd", + "sparc-unknown-linux-gnu", + "sparcv9-sun-solaris", + "thumbv6m-none-eabi", + "thumbv7a-pc-windows-msvc", + "thumbv7a-uwp-windows-msvc", + "thumbv7em-none-eabi", + "thumbv7em-none-eabihf", + "thumbv7m-none-eabi", + "thumbv7neon-linux-androideabi", + "thumbv7neon-unknown-linux-gnueabihf", + "thumbv7neon-unknown-linux-musleabihf", + "thumbv8m.base-none-eabi", + "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", + "wasm32-experimental-emscripten", + "wasm32-unknown-emscripten", + "wasm32-unknown-unknown", + "wasm64-unknown-unknown", + "wasm32-wasi", + "wasm64-wasi", + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fortanix-unknown-sgx", + "x86_64-fuchsia", + "x86_64-linux-android", + "x86_64-linux-kernel", + "x86_64-apple-macosx10.7.0", + "x86_64-pc-solaris", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-rumprun-netbsd", + "x86_64-sun-solaris", + "x86_64-unknown-bitrig", + "x86_64-unknown-cloudabi", + "x86_64-unknown-dragonfly", + "x86_64-unknown-freebsd", + "x86_64-unknown-haiku", + "x86_64-unknown-hermit", + "x86_64-unknown-hermit-kernel", + "x86_64-unknown-illumos", + "x86_64-unknown-l4re-uclibc", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-gnux32", + "x86_64-unknown-linux-musl", + "x86_64-unknown-netbsd", + "x86_64-unknown-openbsd", + "x86_64-unknown-redox", + "x86_64-unknown-uefi", + "x86_64-uwp-windows-gnu", + "x86_64-uwp-windows-msvc", + "x86_64-wrs-vxworks", + ]; + + for target in targets.iter() { + let t = Triple::from_str(target).expect("can't parse target"); + assert_ne!(t.architecture, Architecture::Unknown); + assert_eq!(t.to_string(), *target); + } + } + + #[test] + fn thumbv7em_none_eabihf() { + let t = Triple::from_str("thumbv7em-none-eabihf").expect("can't parse target"); + assert_eq!( + t.architecture, + Architecture::Arm(ArmArchitecture::Thumbv7em) + ); + assert_eq!(t.vendor, Vendor::Unknown); + assert_eq!(t.operating_system, OperatingSystem::None_); + assert_eq!(t.environment, Environment::Eabihf); + assert_eq!(t.binary_format, BinaryFormat::Elf); + } + + #[test] + fn custom_vendors() { + // Test various invalid cases. + assert!(Triple::from_str("x86_64--linux").is_err()); + assert!(Triple::from_str("x86_64-42-linux").is_err()); + assert!(Triple::from_str("x86_64-__customvendor__-linux").is_err()); + assert!(Triple::from_str("x86_64-^-linux").is_err()); + assert!(Triple::from_str("x86_64- -linux").is_err()); + assert!(Triple::from_str("x86_64-CustomVendor-linux").is_err()); + assert!(Triple::from_str("x86_64-linux-linux").is_err()); + assert!(Triple::from_str("x86_64-x86_64-linux").is_err()); + assert!(Triple::from_str("x86_64-elf-linux").is_err()); + assert!(Triple::from_str("x86_64-gnu-linux").is_err()); + assert!(Triple::from_str("x86_64-linux-customvendor").is_err()); + assert!(Triple::from_str("customvendor").is_err()); + assert!(Triple::from_str("customvendor-x86_64").is_err()); + assert!(Triple::from_str("x86_64-").is_err()); + assert!(Triple::from_str("x86_64--").is_err()); + + // Test various Unicode things. + assert!( + Triple::from_str("x86_64-𝓬𝓾𝓼𝓽𝓸𝓶𝓿𝓮𝓷𝓭𝓸𝓻-linux").is_err(), + "unicode font hazard" + ); + assert!( + Triple::from_str("x86_64-ćúśtőḿvéńdőŕ-linux").is_err(), + "diacritical mark stripping hazard" + ); + assert!( + Triple::from_str("x86_64-customvendοr-linux").is_err(), + "homoglyph hazard" + ); + assert!(Triple::from_str("x86_64-customvendor-linux").is_ok()); + assert!( + Triple::from_str("x86_64-ffi-linux").is_err(), + "normalization hazard" + ); + assert!(Triple::from_str("x86_64-ffi-linux").is_ok()); + assert!( + Triple::from_str("x86_64-customvendor-linux").is_err(), + "zero-width character hazard" + ); + assert!( + Triple::from_str("x86_64-customvendor-linux").is_err(), + "BOM hazard" + ); + + // Test some valid cases. + let t = Triple::from_str("x86_64-customvendor-linux") + .expect("can't parse target with custom vendor"); + assert_eq!(t.architecture, Architecture::X86_64); + assert_eq!( + t.vendor, + Vendor::Custom(CustomVendor::Static("customvendor")) + ); + assert_eq!(t.operating_system, OperatingSystem::Linux); + assert_eq!(t.environment, Environment::Unknown); + assert_eq!(t.binary_format, BinaryFormat::Elf); + assert_eq!(t.to_string(), "x86_64-customvendor-linux"); + + let t = + Triple::from_str("x86_64-customvendor").expect("can't parse target with custom vendor"); + assert_eq!(t.architecture, Architecture::X86_64); + assert_eq!( + t.vendor, + Vendor::Custom(CustomVendor::Static("customvendor")) + ); + assert_eq!(t.operating_system, OperatingSystem::Unknown); + assert_eq!(t.environment, Environment::Unknown); + assert_eq!(t.binary_format, BinaryFormat::Unknown); + + assert_eq!( + Triple::from_str("unknown-foo"), + Ok(Triple { + architecture: Architecture::Unknown, + vendor: Vendor::Custom(CustomVendor::Static("foo")), + operating_system: OperatingSystem::Unknown, + environment: Environment::Unknown, + binary_format: BinaryFormat::Unknown, + }) + ); + } +} diff --git a/third_party/rust/target-lexicon/src/triple.rs b/third_party/rust/target-lexicon/src/triple.rs new file mode 100644 index 0000000000..a0e2735b99 --- /dev/null +++ b/third_party/rust/target-lexicon/src/triple.rs @@ -0,0 +1,372 @@ +// This file defines the `Triple` type and support code shared by all targets. + +use crate::data_model::CDataModel; +use crate::parse_error::ParseError; +use crate::targets::{ + default_binary_format, Architecture, ArmArchitecture, BinaryFormat, Environment, + OperatingSystem, Vendor, +}; +use alloc::borrow::ToOwned; +use core::fmt; +use core::str::FromStr; + +/// The target memory endianness. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum Endianness { + Little, + Big, +} + +/// The width of a pointer (in the default address space). +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] +pub enum PointerWidth { + U16, + U32, + U64, +} + +impl PointerWidth { + /// Return the number of bits in a pointer. + pub fn bits(self) -> u8 { + match self { + Self::U16 => 16, + Self::U32 => 32, + Self::U64 => 64, + } + } + + /// Return the number of bytes in a pointer. + /// + /// For these purposes, there are 8 bits in a byte. + pub fn bytes(self) -> u8 { + match self { + Self::U16 => 2, + Self::U32 => 4, + Self::U64 => 8, + } + } +} + +/// The calling convention, which specifies things like which registers are +/// used for passing arguments, which registers are callee-saved, and so on. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CallingConvention { + /// "System V", which is used on most Unix-like platfoms. Note that the + /// specific conventions vary between hardware architectures; for example, + /// x86-32's "System V" is entirely different from x86-64's "System V". + SystemV, + + /// The WebAssembly C ABI. + /// https://github.com/WebAssembly/tool-conventions/blob/master/BasicCABI.md + WasmBasicCAbi, + + /// "Windows Fastcall", which is used on Windows. Note that like "System V", + /// this varies between hardware architectures. On x86-32 it describes what + /// Windows documentation calls "fastcall", and on x86-64 it describes what + /// Windows documentation often just calls the Windows x64 calling convention + /// (though the compiler still recognizes "fastcall" as an alias for it). + WindowsFastcall, +} + +/// A target "triple". Historically such things had three fields, though they've +/// added additional fields over time. +/// +/// Note that `Triple` doesn't implement `Default` itself. If you want a type +/// which defaults to the host triple, or defaults to unknown-unknown-unknown, +/// use `DefaultToHost` or `DefaultToUnknown`, respectively. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Triple { + /// The "architecture" (and sometimes the subarchitecture). + pub architecture: Architecture, + /// The "vendor" (whatever that means). + pub vendor: Vendor, + /// The "operating system" (sometimes also the environment). + pub operating_system: OperatingSystem, + /// The "environment" on top of the operating system (often omitted for + /// operating systems with a single predominant environment). + pub environment: Environment, + /// The "binary format" (rarely used). + pub binary_format: BinaryFormat, +} + +impl Triple { + /// Return the endianness of this target's architecture. + pub fn endianness(&self) -> Result<Endianness, ()> { + self.architecture.endianness() + } + + /// Return the pointer width of this target's architecture. + pub fn pointer_width(&self) -> Result<PointerWidth, ()> { + self.architecture.pointer_width() + } + + /// Return the default calling convention for the given target triple. + pub fn default_calling_convention(&self) -> Result<CallingConvention, ()> { + Ok(match self.operating_system { + OperatingSystem::Bitrig + | OperatingSystem::Cloudabi + | OperatingSystem::Darwin + | OperatingSystem::Dragonfly + | OperatingSystem::Freebsd + | OperatingSystem::Fuchsia + | OperatingSystem::Haiku + | OperatingSystem::Hermit + | OperatingSystem::Ios + | OperatingSystem::L4re + | OperatingSystem::Linux + | OperatingSystem::MacOSX { .. } + | OperatingSystem::Netbsd + | OperatingSystem::Openbsd + | OperatingSystem::Redox + | OperatingSystem::Solaris => CallingConvention::SystemV, + OperatingSystem::Windows => CallingConvention::WindowsFastcall, + OperatingSystem::Nebulet + | OperatingSystem::Emscripten + | OperatingSystem::Wasi + | OperatingSystem::Unknown => match self.architecture { + Architecture::Wasm32 => CallingConvention::WasmBasicCAbi, + _ => return Err(()), + }, + _ => return Err(()), + }) + } + + /// The C data model for a given target. If the model is not known, returns `Err(())`. + pub fn data_model(&self) -> Result<CDataModel, ()> { + match self.pointer_width()? { + PointerWidth::U64 => { + if self.operating_system == OperatingSystem::Windows { + Ok(CDataModel::LLP64) + } else if self.default_calling_convention() == Ok(CallingConvention::SystemV) + || self.architecture == Architecture::Wasm64 + { + Ok(CDataModel::LP64) + } else { + Err(()) + } + } + PointerWidth::U32 => { + if self.operating_system == OperatingSystem::Windows + || self.default_calling_convention() == Ok(CallingConvention::SystemV) + || self.architecture == Architecture::Wasm32 + { + Ok(CDataModel::ILP32) + } else { + Err(()) + } + } + // TODO: on 16-bit machines there is usually a distinction + // between near-pointers and far-pointers. + // Additionally, code pointers sometimes have a different size than data pointers. + // We don't handle this case. + PointerWidth::U16 => Err(()), + } + } + + /// Return a `Triple` with all unknown fields. + pub fn unknown() -> Self { + Self { + architecture: Architecture::Unknown, + vendor: Vendor::Unknown, + operating_system: OperatingSystem::Unknown, + environment: Environment::Unknown, + binary_format: BinaryFormat::Unknown, + } + } +} + +impl fmt::Display for Triple { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let implied_binary_format = default_binary_format(&self); + + write!(f, "{}", self.architecture)?; + if self.vendor == Vendor::Unknown + && ((self.operating_system == OperatingSystem::Linux + && (self.environment == Environment::Android + || self.environment == Environment::Androideabi + || self.environment == Environment::Kernel)) + || self.operating_system == OperatingSystem::Fuchsia + || self.operating_system == OperatingSystem::Wasi + || (self.operating_system == OperatingSystem::None_ + && (self.architecture == Architecture::Arm(ArmArchitecture::Armebv7r) + || self.architecture == Architecture::Arm(ArmArchitecture::Armv7a) + || self.architecture == Architecture::Arm(ArmArchitecture::Armv7r) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv6m) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7em) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv7m) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mBase) + || self.architecture == Architecture::Arm(ArmArchitecture::Thumbv8mMain) + || self.architecture == Architecture::Msp430 + || self.architecture == Architecture::X86_64))) + { + // As a special case, omit the vendor for Android, Fuchsia, Wasi, and sometimes + // None_, depending on the hardware architecture. This logic is entirely + // ad-hoc, and is just sufficient to handle the current set of recognized + // triples. + write!(f, "-{}", self.operating_system)?; + } else { + write!(f, "-{}-{}", self.vendor, self.operating_system)?; + } + if self.environment != Environment::Unknown { + write!(f, "-{}", self.environment)?; + } + + if self.binary_format != implied_binary_format { + write!(f, "-{}", self.binary_format)?; + } + Ok(()) + } +} + +impl FromStr for Triple { + type Err = ParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let mut parts = s.split('-'); + let mut result = Self::unknown(); + let mut current_part; + + current_part = parts.next(); + if let Some(s) = current_part { + if let Ok(architecture) = Architecture::from_str(s) { + result.architecture = architecture; + current_part = parts.next(); + } else { + // Insist that the triple start with a valid architecture. + return Err(ParseError::UnrecognizedArchitecture(s.to_owned())); + } + } + + let mut has_vendor = false; + let mut has_operating_system = false; + if let Some(s) = current_part { + if let Ok(vendor) = Vendor::from_str(s) { + has_vendor = true; + result.vendor = vendor; + current_part = parts.next(); + } + } + + if !has_operating_system { + if let Some(s) = current_part { + if let Ok(operating_system) = OperatingSystem::from_str(s) { + has_operating_system = true; + result.operating_system = operating_system; + current_part = parts.next(); + } + } + } + + let mut has_environment = false; + if let Some(s) = current_part { + if let Ok(environment) = Environment::from_str(s) { + has_environment = true; + result.environment = environment; + current_part = parts.next(); + } + } + + let mut has_binary_format = false; + if let Some(s) = current_part { + if let Ok(binary_format) = BinaryFormat::from_str(s) { + has_binary_format = true; + result.binary_format = binary_format; + current_part = parts.next(); + } + } + + // The binary format is frequently omitted; if that's the case here, + // infer it from the other fields. + if !has_binary_format { + result.binary_format = default_binary_format(&result); + } + + if let Some(s) = current_part { + Err( + if !has_vendor && !has_operating_system && !has_environment && !has_binary_format { + ParseError::UnrecognizedVendor(s.to_owned()) + } else if !has_operating_system && !has_environment && !has_binary_format { + ParseError::UnrecognizedOperatingSystem(s.to_owned()) + } else if !has_environment && !has_binary_format { + ParseError::UnrecognizedEnvironment(s.to_owned()) + } else if !has_binary_format { + ParseError::UnrecognizedBinaryFormat(s.to_owned()) + } else { + ParseError::UnrecognizedField(s.to_owned()) + }, + ) + } else { + Ok(result) + } + } +} + +/// A convenient syntax for triple literals. +/// +/// This currently expands to code that just calls `Triple::from_str` and does +/// an `expect`, though in the future it would be cool to use procedural macros +/// or so to report errors at compile time instead. +#[macro_export] +macro_rules! triple { + ($str:tt) => { + target_lexicon::Triple::from_str($str).expect("invalid triple literal") + }; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_errors() { + assert_eq!( + Triple::from_str(""), + Err(ParseError::UnrecognizedArchitecture("".to_owned())) + ); + assert_eq!( + Triple::from_str("foo"), + Err(ParseError::UnrecognizedArchitecture("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-foo"), + Err(ParseError::UnrecognizedOperatingSystem("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedEnvironment("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedBinaryFormat("foo".to_owned())) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-unknown-foo"), + Err(ParseError::UnrecognizedField("foo".to_owned())) + ); + } + + #[test] + fn defaults() { + assert_eq!( + Triple::from_str("unknown-unknown-unknown"), + Ok(Triple::unknown()) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown"), + Ok(Triple::unknown()) + ); + assert_eq!( + Triple::from_str("unknown-unknown-unknown-unknown-unknown"), + Ok(Triple::unknown()) + ); + } + + #[test] + fn unknown_properties() { + assert_eq!(Triple::unknown().endianness(), Err(())); + assert_eq!(Triple::unknown().pointer_width(), Err(())); + assert_eq!(Triple::unknown().default_calling_convention(), Err(())); + } +} |