commit
0aaa9ea5c0
1501 changed files with 30073 additions and 9904 deletions
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
|
|
@ -418,14 +418,14 @@ jobs:
|
|||
os: windows-latest-xl
|
||||
- name: i686-mingw-1
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
|
||||
SCRIPT: make ci-mingw-subset-1
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-latest-xl
|
||||
- name: i686-mingw-2
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
|
||||
SCRIPT: make ci-mingw-subset-2
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
|
|
@ -433,21 +433,21 @@ jobs:
|
|||
- name: x86_64-mingw-1
|
||||
env:
|
||||
SCRIPT: make ci-mingw-subset-1
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-latest-xl
|
||||
- name: x86_64-mingw-2
|
||||
env:
|
||||
SCRIPT: make ci-mingw-subset-2
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-latest-xl
|
||||
- name: dist-x86_64-msvc
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin"
|
||||
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc src/ci/pgo.sh python x.py dist bootstrap --include-default-paths
|
||||
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: windows-latest-xl
|
||||
- name: dist-i686-msvc
|
||||
|
|
@ -465,7 +465,7 @@ jobs:
|
|||
os: windows-latest-xl
|
||||
- name: dist-i686-mingw
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||
CUSTOM_MINGW: 1
|
||||
|
|
@ -474,7 +474,7 @@ jobs:
|
|||
- name: dist-x86_64-mingw
|
||||
env:
|
||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler"
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
|
|
|
|||
40
Cargo.lock
40
Cargo.lock
|
|
@ -351,7 +351,7 @@ dependencies = [
|
|||
"cargo-test-macro",
|
||||
"cargo-test-support",
|
||||
"cargo-util",
|
||||
"clap 4.1.1",
|
||||
"clap 4.1.4",
|
||||
"crates-io",
|
||||
"curl",
|
||||
"curl-sys",
|
||||
|
|
@ -655,9 +655,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.1"
|
||||
version = "4.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
|
||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive 4.1.0",
|
||||
|
|
@ -675,7 +675,7 @@ version = "4.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
|
||||
dependencies = [
|
||||
"clap 4.1.1",
|
||||
"clap 4.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -724,7 +724,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.68"
|
||||
version = "0.1.69"
|
||||
dependencies = [
|
||||
"clippy_lints",
|
||||
"clippy_utils",
|
||||
|
|
@ -766,7 +766,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.68"
|
||||
version = "0.1.69"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.14.0",
|
||||
"clippy_utils",
|
||||
|
|
@ -789,7 +789,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.68"
|
||||
version = "0.1.69"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"if_chain",
|
||||
|
|
@ -1168,7 +1168,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.68"
|
||||
version = "0.1.69"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"quote",
|
||||
|
|
@ -1799,9 +1799,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.16.1"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc"
|
||||
checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
|
|
@ -2294,7 +2294,7 @@ name = "jsondoclint"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.1",
|
||||
"clap 4.1.4",
|
||||
"fs-err",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
|
|
@ -2365,9 +2365,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.14.2+1.5.1"
|
||||
version = "0.14.1+1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4"
|
||||
checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -2557,7 +2557,7 @@ dependencies = [
|
|||
"ammonia",
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap 4.1.1",
|
||||
"clap 4.1.4",
|
||||
"clap_complete",
|
||||
"elasticlunr-rs",
|
||||
"env_logger 0.10.0",
|
||||
|
|
@ -3528,7 +3528,7 @@ dependencies = [
|
|||
name = "rustbook"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 4.1.1",
|
||||
"clap 4.1.4",
|
||||
"env_logger 0.7.1",
|
||||
"mdbook",
|
||||
]
|
||||
|
|
@ -3672,6 +3672,7 @@ name = "rustc_ast"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"memchr",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
|
|
@ -3729,6 +3730,7 @@ name = "rustc_ast_pretty"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_ast",
|
||||
"rustc_parse_format",
|
||||
"rustc_span",
|
||||
]
|
||||
|
||||
|
|
@ -4926,7 +4928,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustfmt-config_proc_macro"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -4936,7 +4938,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustfmt-nightly"
|
||||
version = "1.5.1"
|
||||
version = "1.5.2"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"anyhow",
|
||||
|
|
@ -5214,9 +5216,9 @@ checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
|
|||
|
||||
[[package]]
|
||||
name = "snap"
|
||||
version = "1.0.1"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"
|
||||
checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831"
|
||||
|
||||
[[package]]
|
||||
name = "snapbox"
|
||||
|
|
|
|||
103
RELEASES.md
103
RELEASES.md
|
|
@ -1,3 +1,106 @@
|
|||
Version 1.67.0 (2023-01-26)
|
||||
==========================
|
||||
|
||||
<a id="1.67.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
|
||||
- [Make `Sized` predicates coinductive, allowing cycles.](https://github.com/rust-lang/rust/pull/100386/)
|
||||
- [`#[must_use]` annotations on `async fn` also affect the `Future::Output`.](https://github.com/rust-lang/rust/pull/100633/)
|
||||
- [Elaborate supertrait obligations when deducing closure signatures.](https://github.com/rust-lang/rust/pull/101834/)
|
||||
- [Invalid literals are no longer an error under `cfg(FALSE)`.](https://github.com/rust-lang/rust/pull/102944/)
|
||||
- [Unreserve braced enum variants in value namespace.](https://github.com/rust-lang/rust/pull/103578/)
|
||||
|
||||
<a id="1.67.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
|
||||
- [Enable varargs support for calling conventions other than `C` or `cdecl`.](https://github.com/rust-lang/rust/pull/97971/)
|
||||
- [Add new MIR constant propagation based on dataflow analysis.](https://github.com/rust-lang/rust/pull/101168/)
|
||||
- [Optimize field ordering by grouping m\*2^n-sized fields with equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/)
|
||||
- [Stabilize native library modifier `verbatim`.](https://github.com/rust-lang/rust/pull/104360/)
|
||||
|
||||
Added and removed targets:
|
||||
|
||||
- [Add a tier 3 target for PowerPC on AIX](https://github.com/rust-lang/rust/pull/102293/), `powerpc64-ibm-aix`.
|
||||
- [Add a tier 3 target for the Sony PlayStation 1](https://github.com/rust-lang/rust/pull/102689/), `mipsel-sony-psx`.
|
||||
- [Add tier 3 `no_std` targets for the QNX Neutrino RTOS](https://github.com/rust-lang/rust/pull/102701/),
|
||||
`aarch64-unknown-nto-qnx710` and `x86_64-pc-nto-qnx710`.
|
||||
- [Remove tier 3 `linuxkernel` targets](https://github.com/rust-lang/rust/pull/104015/) (not used by the actual kernel).
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
<a id="1.67.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
- [Merge `crossbeam-channel` into `std::sync::mpsc`.](https://github.com/rust-lang/rust/pull/93563/)
|
||||
- [Fix inconsistent rounding of 0.5 when formatted to 0 decimal places.](https://github.com/rust-lang/rust/pull/102935/)
|
||||
- [Derive `Eq` and `Hash` for `ControlFlow`.](https://github.com/rust-lang/rust/pull/103084/)
|
||||
- [Don't build `compiler_builtins` with `-C panic=abort`.](https://github.com/rust-lang/rust/pull/103786/)
|
||||
|
||||
<a id="1.67.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`{integer}::checked_ilog`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog)
|
||||
- [`{integer}::checked_ilog2`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog2)
|
||||
- [`{integer}::checked_ilog10`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.checked_ilog10)
|
||||
- [`{integer}::ilog`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog)
|
||||
- [`{integer}::ilog2`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog2)
|
||||
- [`{integer}::ilog10`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.ilog10)
|
||||
- [`NonZeroU*::ilog2`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog2)
|
||||
- [`NonZeroU*::ilog10`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#method.ilog10)
|
||||
- [`NonZero*::BITS`](https://doc.rust-lang.org/stable/std/num/struct.NonZeroU32.html#associatedconstant.BITS)
|
||||
|
||||
These APIs are now stable in const contexts:
|
||||
|
||||
- [`char::from_u32`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_u32)
|
||||
- [`char::from_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.from_digit)
|
||||
- [`char::to_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_digit)
|
||||
- [`core::char::from_u32`](https://doc.rust-lang.org/stable/core/char/fn.from_u32.html)
|
||||
- [`core::char::from_digit`](https://doc.rust-lang.org/stable/core/char/fn.from_digit.html)
|
||||
|
||||
<a id="1.67.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
|
||||
- [The layout of `repr(Rust)` types now groups m\*2^n-sized fields with
|
||||
equivalently aligned ones.](https://github.com/rust-lang/rust/pull/102750/)
|
||||
This is intended to be an optimization, but it is also known to increase type
|
||||
sizes in a few cases for the placement of enum tags. As a reminder, the layout
|
||||
of `repr(Rust)` types is an implementation detail, subject to change.
|
||||
- [0.5 now rounds to 0 when formatted to 0 decimal places.](https://github.com/rust-lang/rust/pull/102935/)
|
||||
This makes it consistent with the rest of floating point formatting that
|
||||
rounds ties toward even digits.
|
||||
- [Chains of `&&` and `||` will now drop temporaries from their sub-expressions in
|
||||
evaluation order, left-to-right.](https://github.com/rust-lang/rust/pull/103293/)
|
||||
Previously, it was "twisted" such that the _first_ expression dropped its
|
||||
temporaries _last_, after all of the other expressions dropped in order.
|
||||
- [Underscore suffixes on string literals are now a hard error.](https://github.com/rust-lang/rust/pull/103914/)
|
||||
This has been a future-compatibility warning since 1.20.0.
|
||||
- [Stop passing `-export-dynamic` to `wasm-ld`.](https://github.com/rust-lang/rust/pull/105405/)
|
||||
- [`main` is now mangled as `__main_void` on `wasm32-wasi`.](https://github.com/rust-lang/rust/pull/105468/)
|
||||
- [Cargo now emits an error if there are multiple registries in the configuration
|
||||
with the same index URL.](https://github.com/rust-lang/cargo/pull/10592)
|
||||
|
||||
<a id="1.67.0-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Rewrite LLVM's archive writer in Rust.](https://github.com/rust-lang/rust/pull/97485/)
|
||||
|
||||
Version 1.66.1 (2023-01-10)
|
||||
===========================
|
||||
|
||||
|
|
|
|||
|
|
@ -267,6 +267,9 @@ impl TargetDataLayout {
|
|||
["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
|
||||
["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
|
||||
["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?,
|
||||
// FIXME(erikdesjardins): we should be parsing nonzero address spaces
|
||||
// this will require replacing TargetDataLayout::{pointer_size,pointer_align}
|
||||
// with e.g. `fn pointer_size_in(AddressSpace)`
|
||||
[p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => {
|
||||
dl.pointer_size = size(s, p)?;
|
||||
dl.pointer_align = align(a, p)?;
|
||||
|
|
@ -861,7 +864,7 @@ pub enum Primitive {
|
|||
Int(Integer, bool),
|
||||
F32,
|
||||
F64,
|
||||
Pointer,
|
||||
Pointer(AddressSpace),
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
|
|
@ -872,7 +875,10 @@ impl Primitive {
|
|||
Int(i, _) => i.size(),
|
||||
F32 => Size::from_bits(32),
|
||||
F64 => Size::from_bits(64),
|
||||
Pointer => dl.pointer_size,
|
||||
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
|
||||
// different address spaces can have different sizes
|
||||
// (but TargetDataLayout doesn't currently parse that part of the DL string)
|
||||
Pointer(_) => dl.pointer_size,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -883,26 +889,12 @@ impl Primitive {
|
|||
Int(i, _) => i.align(dl),
|
||||
F32 => dl.f32_align,
|
||||
F64 => dl.f64_align,
|
||||
Pointer => dl.pointer_align,
|
||||
// FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
|
||||
// different address spaces can have different alignments
|
||||
// (but TargetDataLayout doesn't currently parse that part of the DL string)
|
||||
Pointer(_) => dl.pointer_align,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(eddyb) remove, it's trivial thanks to `matches!`.
|
||||
#[inline]
|
||||
pub fn is_float(self) -> bool {
|
||||
matches!(self, F32 | F64)
|
||||
}
|
||||
|
||||
// FIXME(eddyb) remove, it's completely unused.
|
||||
#[inline]
|
||||
pub fn is_int(self) -> bool {
|
||||
matches!(self, Int(..))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ptr(self) -> bool {
|
||||
matches!(self, Pointer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Inclusive wrap-around range of valid values, that is, if
|
||||
|
|
@ -1188,7 +1180,8 @@ impl FieldsShape {
|
|||
/// An identifier that specifies the address space that some operation
|
||||
/// should operate on. Special address spaces have an effect on code generation,
|
||||
/// depending on the target and the address spaces it implements.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||
pub struct AddressSpace(pub u32);
|
||||
|
||||
impl AddressSpace {
|
||||
|
|
@ -1468,7 +1461,6 @@ pub struct PointeeInfo {
|
|||
pub size: Size,
|
||||
pub align: Align,
|
||||
pub safe: Option<PointerKind>,
|
||||
pub address_space: AddressSpace,
|
||||
}
|
||||
|
||||
/// Used in `might_permit_raw_init` to indicate the kind of initialisation
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
bitflags = "1.2.1"
|
||||
memchr = "2.5.0"
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
//! - [`Attribute`]: Metadata associated with item.
|
||||
//! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.
|
||||
|
||||
pub use crate::format::*;
|
||||
pub use crate::util::parser::ExprPrecedence;
|
||||
pub use GenericArgs::*;
|
||||
pub use UnsafeSource::*;
|
||||
|
|
@ -1269,6 +1270,7 @@ impl Expr {
|
|||
ExprKind::Try(..) => ExprPrecedence::Try,
|
||||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
||||
ExprKind::Yeet(..) => ExprPrecedence::Yeet,
|
||||
ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs,
|
||||
ExprKind::Err => ExprPrecedence::Err,
|
||||
}
|
||||
}
|
||||
|
|
@ -1499,6 +1501,9 @@ pub enum ExprKind {
|
|||
/// with a `ByteStr` literal.
|
||||
IncludedBytes(Lrc<[u8]>),
|
||||
|
||||
/// A `format_args!()` expression.
|
||||
FormatArgs(P<FormatArgs>),
|
||||
|
||||
/// Placeholder for an expression that wasn't syntactically well formed in some way.
|
||||
Err,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::Expr;
|
||||
use crate::ptr::P;
|
||||
use crate::Expr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
|
@ -39,7 +39,7 @@ use rustc_span::Span;
|
|||
/// Basically the "AST" for a complete `format_args!()`.
|
||||
///
|
||||
/// E.g., `format_args!("hello {name}");`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct FormatArgs {
|
||||
pub span: Span,
|
||||
pub template: Vec<FormatArgsPiece>,
|
||||
|
|
@ -49,7 +49,7 @@ pub struct FormatArgs {
|
|||
/// A piece of a format template string.
|
||||
///
|
||||
/// E.g. "hello" or "{name}".
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum FormatArgsPiece {
|
||||
Literal(Symbol),
|
||||
Placeholder(FormatPlaceholder),
|
||||
|
|
@ -59,7 +59,7 @@ pub enum FormatArgsPiece {
|
|||
///
|
||||
/// E.g. `1, 2, name="ferris", n=3`,
|
||||
/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct FormatArguments {
|
||||
arguments: Vec<FormatArgument>,
|
||||
num_unnamed_args: usize,
|
||||
|
|
@ -67,6 +67,12 @@ pub struct FormatArguments {
|
|||
names: FxHashMap<Symbol, usize>,
|
||||
}
|
||||
|
||||
// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930.
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl Sync for FormatArguments {}
|
||||
#[cfg(parallel_compiler)]
|
||||
unsafe impl Send for FormatArguments {}
|
||||
|
||||
impl FormatArguments {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
|
@ -121,18 +127,22 @@ impl FormatArguments {
|
|||
&self.arguments[..self.num_explicit_args]
|
||||
}
|
||||
|
||||
pub fn into_vec(self) -> Vec<FormatArgument> {
|
||||
self.arguments
|
||||
pub fn all_args(&self) -> &[FormatArgument] {
|
||||
&self.arguments[..]
|
||||
}
|
||||
|
||||
pub fn all_args_mut(&mut self) -> &mut [FormatArgument] {
|
||||
&mut self.arguments[..]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct FormatArgument {
|
||||
pub kind: FormatArgumentKind,
|
||||
pub expr: P<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum FormatArgumentKind {
|
||||
/// `format_args(…, arg)`
|
||||
Normal,
|
||||
|
|
@ -152,7 +162,7 @@ impl FormatArgumentKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub struct FormatPlaceholder {
|
||||
/// Index into [`FormatArgs::arguments`].
|
||||
pub argument: FormatArgPosition,
|
||||
|
|
@ -164,7 +174,7 @@ pub struct FormatPlaceholder {
|
|||
pub format_options: FormatOptions,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub struct FormatArgPosition {
|
||||
/// Which argument this position refers to (Ok),
|
||||
/// or would've referred to if it existed (Err).
|
||||
|
|
@ -175,7 +185,7 @@ pub struct FormatArgPosition {
|
|||
pub span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub enum FormatArgPositionKind {
|
||||
/// `{}` or `{:.*}`
|
||||
Implicit,
|
||||
|
|
@ -185,7 +195,7 @@ pub enum FormatArgPositionKind {
|
|||
Named,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum FormatTrait {
|
||||
/// `{}`
|
||||
Display,
|
||||
|
|
@ -207,7 +217,7 @@ pub enum FormatTrait {
|
|||
UpperHex,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)]
|
||||
pub struct FormatOptions {
|
||||
/// The width. E.g. `{:5}` or `{:width$}`.
|
||||
pub width: Option<FormatCount>,
|
||||
|
|
@ -217,11 +227,33 @@ pub struct FormatOptions {
|
|||
pub alignment: Option<FormatAlignment>,
|
||||
/// The fill character. E.g. the `.` in `{:.>10}`.
|
||||
pub fill: Option<char>,
|
||||
/// The `+`, `-`, `0`, `#`, `x?` and `X?` flags.
|
||||
pub flags: u32,
|
||||
/// The `+` or `-` flag.
|
||||
pub sign: Option<FormatSign>,
|
||||
/// The `#` flag.
|
||||
pub alternate: bool,
|
||||
/// The `0` flag. E.g. the `0` in `{:02x}`.
|
||||
pub zero_pad: bool,
|
||||
/// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
|
||||
pub debug_hex: Option<FormatDebugHex>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub enum FormatSign {
|
||||
/// The `+` flag.
|
||||
Plus,
|
||||
/// The `-` flag.
|
||||
Minus,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub enum FormatDebugHex {
|
||||
/// The `x` flag in `{:x?}`.
|
||||
Lower,
|
||||
/// The `X` flag in `{:X?}`.
|
||||
Upper,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub enum FormatAlignment {
|
||||
/// `{:<}`
|
||||
Left,
|
||||
|
|
@ -231,7 +263,7 @@ pub enum FormatAlignment {
|
|||
Center,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
|
||||
pub enum FormatCount {
|
||||
/// `{:5}` or `{:.5}`
|
||||
Literal(usize),
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(slice_internals)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
|
|
@ -42,6 +41,7 @@ pub mod ast_traits;
|
|||
pub mod attr;
|
||||
pub mod entry;
|
||||
pub mod expand;
|
||||
pub mod format;
|
||||
pub mod mut_visit;
|
||||
pub mod node_id;
|
||||
pub mod ptr;
|
||||
|
|
@ -51,6 +51,7 @@ pub mod visit;
|
|||
|
||||
pub use self::ast::*;
|
||||
pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens};
|
||||
pub use self::format::*;
|
||||
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
|
||||
|
|
|
|||
|
|
@ -297,6 +297,10 @@ pub trait MutVisitor: Sized {
|
|||
fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) {
|
||||
noop_visit_inline_asm_sym(sym, self)
|
||||
}
|
||||
|
||||
fn visit_format_args(&mut self, fmt: &mut FormatArgs) {
|
||||
noop_visit_format_args(fmt, self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
|
||||
|
|
@ -1284,6 +1288,15 @@ pub fn noop_visit_inline_asm_sym<T: MutVisitor>(
|
|||
vis.visit_path(path);
|
||||
}
|
||||
|
||||
pub fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) {
|
||||
for arg in fmt.arguments.all_args_mut() {
|
||||
if let FormatArgumentKind::Named(name) = &mut arg.kind {
|
||||
vis.visit_ident(name);
|
||||
}
|
||||
vis.visit_expr(&mut arg.expr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_expr<T: MutVisitor>(
|
||||
Expr { kind, id, span, attrs, tokens }: &mut Expr,
|
||||
vis: &mut T,
|
||||
|
|
@ -1425,6 +1438,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
|||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
|
||||
ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
|
||||
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
ExprKind::Struct(se) => {
|
||||
let StructExpr { qself, path, fields, rest } = se.deref_mut();
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ pub enum ExprPrecedence {
|
|||
Try,
|
||||
InlineAsm,
|
||||
Mac,
|
||||
FormatArgs,
|
||||
|
||||
Array,
|
||||
Repeat,
|
||||
|
|
@ -335,7 +336,8 @@ impl ExprPrecedence {
|
|||
| ExprPrecedence::Index
|
||||
| ExprPrecedence::Try
|
||||
| ExprPrecedence::InlineAsm
|
||||
| ExprPrecedence::Mac => PREC_POSTFIX,
|
||||
| ExprPrecedence::Mac
|
||||
| ExprPrecedence::FormatArgs => PREC_POSTFIX,
|
||||
|
||||
// Never need parens
|
||||
ExprPrecedence::Array
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ pub fn contains_text_flow_control_chars(s: &str) -> bool {
|
|||
// U+2069 - E2 81 A9
|
||||
let mut bytes = s.as_bytes();
|
||||
loop {
|
||||
match core::slice::memchr::memchr(0xE2, bytes) {
|
||||
match memchr::memchr(0xE2, bytes) {
|
||||
Some(idx) => {
|
||||
// bytes are valid UTF-8 -> E2 must be followed by two bytes
|
||||
let ch = &bytes[idx..idx + 3];
|
||||
|
|
|
|||
|
|
@ -242,6 +242,9 @@ pub trait Visitor<'ast>: Sized {
|
|||
fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) {
|
||||
walk_inline_asm(self, asm)
|
||||
}
|
||||
fn visit_format_args(&mut self, fmt: &'ast FormatArgs) {
|
||||
walk_format_args(self, fmt)
|
||||
}
|
||||
fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
|
||||
walk_inline_asm_sym(self, sym)
|
||||
}
|
||||
|
|
@ -400,8 +403,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
|
|||
walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
|
||||
visitor.visit_ty(&mutable_type.ty)
|
||||
}
|
||||
TyKind::Tup(tuple_element_types) => {
|
||||
walk_list!(visitor, visit_ty, tuple_element_types);
|
||||
TyKind::Tup(tys) => {
|
||||
walk_list!(visitor, visit_ty, tys);
|
||||
}
|
||||
TyKind::BareFn(function_declaration) => {
|
||||
walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
|
||||
|
|
@ -756,6 +759,15 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineA
|
|||
visitor.visit_path(&sym.path, sym.id);
|
||||
}
|
||||
|
||||
pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) {
|
||||
for arg in fmt.arguments.all_args() {
|
||||
if let FormatArgumentKind::Named(name) = arg.kind {
|
||||
visitor.visit_ident(name);
|
||||
}
|
||||
visitor.visit_expr(&arg.expr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
walk_list!(visitor, visit_attribute, expression.attrs.iter());
|
||||
|
||||
|
|
@ -896,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||
ExprKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||
ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression),
|
||||
ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm),
|
||||
ExprKind::FormatArgs(f) => visitor.visit_format_args(f),
|
||||
ExprKind::Yield(optional_expression) => {
|
||||
walk_list!(visitor, visit_expr, optional_expression);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_hir::def::Res;
|
|||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
|
|
@ -294,6 +294,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::InlineAsm(asm) => {
|
||||
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
|
||||
}
|
||||
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
|
||||
ExprKind::Struct(se) => {
|
||||
let rest = match &se.rest {
|
||||
StructRest::Base(e) => Some(self.lower_expr(e)),
|
||||
|
|
@ -1735,7 +1736,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.expr(span, hir::ExprKind::DropTemps(expr))
|
||||
}
|
||||
|
||||
fn expr_match(
|
||||
pub(super) fn expr_match(
|
||||
&mut self,
|
||||
span: Span,
|
||||
arg: &'hir hir::Expr<'hir>,
|
||||
|
|
@ -1763,7 +1764,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
|
||||
}
|
||||
|
||||
fn expr_call_mut(
|
||||
pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
|
||||
self.expr(
|
||||
sp,
|
||||
hir::ExprKind::Lit(hir::Lit {
|
||||
span: sp,
|
||||
node: ast::LitKind::Int(
|
||||
value as u128,
|
||||
ast::LitIntType::Unsigned(ast::UintTy::Usize),
|
||||
),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
|
||||
self.expr(
|
||||
sp,
|
||||
hir::ExprKind::Lit(hir::Lit {
|
||||
span: sp,
|
||||
node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> {
|
||||
self.expr(sp, hir::ExprKind::Lit(hir::Lit { span: sp, node: ast::LitKind::Char(value) }))
|
||||
}
|
||||
|
||||
pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
|
||||
self.expr(
|
||||
sp,
|
||||
hir::ExprKind::Lit(hir::Lit {
|
||||
span: sp,
|
||||
node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn expr_call_mut(
|
||||
&mut self,
|
||||
span: Span,
|
||||
e: &'hir hir::Expr<'hir>,
|
||||
|
|
@ -1772,7 +1810,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.expr(span, hir::ExprKind::Call(e, args))
|
||||
}
|
||||
|
||||
fn expr_call(
|
||||
pub(super) fn expr_call(
|
||||
&mut self,
|
||||
span: Span,
|
||||
e: &'hir hir::Expr<'hir>,
|
||||
|
|
@ -1814,6 +1852,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
}
|
||||
|
||||
/// `<LangItem>::name`
|
||||
pub(super) fn expr_lang_item_type_relative(
|
||||
&mut self,
|
||||
span: Span,
|
||||
lang_item: hir::LangItem,
|
||||
name: Symbol,
|
||||
) -> hir::Expr<'hir> {
|
||||
let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
|
||||
self.arena.alloc(self.ty(
|
||||
span,
|
||||
hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), None)),
|
||||
)),
|
||||
self.arena.alloc(hir::PathSegment::new(
|
||||
Ident::new(name, span),
|
||||
self.next_id(),
|
||||
Res::Err,
|
||||
)),
|
||||
));
|
||||
self.expr(span, path)
|
||||
}
|
||||
|
||||
pub(super) fn expr_ident(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
|
|
@ -1872,12 +1931,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.expr(b.span, hir::ExprKind::Block(b, None))
|
||||
}
|
||||
|
||||
pub(super) fn expr_array_ref(
|
||||
&mut self,
|
||||
span: Span,
|
||||
elements: &'hir [hir::Expr<'hir>],
|
||||
) -> hir::Expr<'hir> {
|
||||
let addrof = hir::ExprKind::AddrOf(
|
||||
hir::BorrowKind::Ref,
|
||||
hir::Mutability::Not,
|
||||
self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))),
|
||||
);
|
||||
self.expr(span, addrof)
|
||||
}
|
||||
|
||||
pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> {
|
||||
let hir_id = self.next_id();
|
||||
hir::Expr { hir_id, kind, span: self.lower_span(span) }
|
||||
}
|
||||
|
||||
fn expr_field(
|
||||
pub(super) fn expr_field(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
expr: &'hir hir::Expr<'hir>,
|
||||
|
|
@ -1892,7 +1964,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn arm(&mut self, pat: &'hir hir::Pat<'hir>, expr: &'hir hir::Expr<'hir>) -> hir::Arm<'hir> {
|
||||
pub(super) fn arm(
|
||||
&mut self,
|
||||
pat: &'hir hir::Pat<'hir>,
|
||||
expr: &'hir hir::Expr<'hir>,
|
||||
) -> hir::Arm<'hir> {
|
||||
hir::Arm {
|
||||
hir_id: self.next_id(),
|
||||
pat,
|
||||
|
|
|
|||
398
compiler/rustc_ast_lowering/src/format.rs
Normal file
398
compiler/rustc_ast_lowering/src/format.rs
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
use super::LoweringContext;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_span::{
|
||||
sym,
|
||||
symbol::{kw, Ident},
|
||||
Span,
|
||||
};
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
|
||||
expand_format_args(self, sp, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
enum ArgumentType {
|
||||
Format(FormatTrait),
|
||||
Usize,
|
||||
}
|
||||
|
||||
/// Generate a hir expression representing an argument to a format_args invocation.
|
||||
///
|
||||
/// Generates:
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::ArgumentV1>::new_…(arg)
|
||||
/// ```
|
||||
fn make_argument<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
sp: Span,
|
||||
arg: &'hir hir::Expr<'hir>,
|
||||
ty: ArgumentType,
|
||||
) -> hir::Expr<'hir> {
|
||||
use ArgumentType::*;
|
||||
use FormatTrait::*;
|
||||
let new_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
sp,
|
||||
hir::LangItem::FormatArgument,
|
||||
match ty {
|
||||
Format(Display) => sym::new_display,
|
||||
Format(Debug) => sym::new_debug,
|
||||
Format(LowerExp) => sym::new_lower_exp,
|
||||
Format(UpperExp) => sym::new_upper_exp,
|
||||
Format(Octal) => sym::new_octal,
|
||||
Format(Pointer) => sym::new_pointer,
|
||||
Format(Binary) => sym::new_binary,
|
||||
Format(LowerHex) => sym::new_lower_hex,
|
||||
Format(UpperHex) => sym::new_upper_hex,
|
||||
Usize => sym::from_usize,
|
||||
},
|
||||
));
|
||||
ctx.expr_call_mut(sp, new_fn, std::slice::from_ref(arg))
|
||||
}
|
||||
|
||||
/// Generate a hir expression for a format_args Count.
|
||||
///
|
||||
/// Generates:
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::rt::v1::Count>::Is(…)
|
||||
/// ```
|
||||
///
|
||||
/// or
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::rt::v1::Count>::Param(…)
|
||||
/// ```
|
||||
///
|
||||
/// or
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::rt::v1::Count>::Implied
|
||||
/// ```
|
||||
fn make_count<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
sp: Span,
|
||||
count: &Option<FormatCount>,
|
||||
argmap: &mut FxIndexSet<(usize, ArgumentType)>,
|
||||
) -> hir::Expr<'hir> {
|
||||
match count {
|
||||
Some(FormatCount::Literal(n)) => {
|
||||
let count_is = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
sp,
|
||||
hir::LangItem::FormatCount,
|
||||
sym::Is,
|
||||
));
|
||||
let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]);
|
||||
ctx.expr_call_mut(sp, count_is, value)
|
||||
}
|
||||
Some(FormatCount::Argument(arg)) => {
|
||||
if let Ok(arg_index) = arg.index {
|
||||
let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
|
||||
let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
sp,
|
||||
hir::LangItem::FormatCount,
|
||||
sym::Param,
|
||||
));
|
||||
let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, i)]);
|
||||
ctx.expr_call_mut(sp, count_param, value)
|
||||
} else {
|
||||
ctx.expr(sp, hir::ExprKind::Err)
|
||||
}
|
||||
}
|
||||
None => ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatCount, sym::Implied),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a hir expression for a format_args placeholder specification.
|
||||
///
|
||||
/// Generates
|
||||
///
|
||||
/// ```text
|
||||
/// <core::fmt::rt::v1::Argument::new(
|
||||
/// …usize, // position
|
||||
/// '…', // fill
|
||||
/// <core::fmt::rt::v1::Alignment>::…, // alignment
|
||||
/// …u32, // flags
|
||||
/// <core::fmt::rt::v1::Count::…>, // width
|
||||
/// <core::fmt::rt::v1::Count::…>, // precision
|
||||
/// )
|
||||
/// ```
|
||||
fn make_format_spec<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
sp: Span,
|
||||
placeholder: &FormatPlaceholder,
|
||||
argmap: &mut FxIndexSet<(usize, ArgumentType)>,
|
||||
) -> hir::Expr<'hir> {
|
||||
let position = match placeholder.argument.index {
|
||||
Ok(arg_index) => {
|
||||
let (i, _) =
|
||||
argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
|
||||
ctx.expr_usize(sp, i)
|
||||
}
|
||||
Err(_) => ctx.expr(sp, hir::ExprKind::Err),
|
||||
};
|
||||
let &FormatOptions {
|
||||
ref width,
|
||||
ref precision,
|
||||
alignment,
|
||||
fill,
|
||||
sign,
|
||||
alternate,
|
||||
zero_pad,
|
||||
debug_hex,
|
||||
} = &placeholder.format_options;
|
||||
let fill = ctx.expr_char(sp, fill.unwrap_or(' '));
|
||||
let align = ctx.expr_lang_item_type_relative(
|
||||
sp,
|
||||
hir::LangItem::FormatAlignment,
|
||||
match alignment {
|
||||
Some(FormatAlignment::Left) => sym::Left,
|
||||
Some(FormatAlignment::Right) => sym::Right,
|
||||
Some(FormatAlignment::Center) => sym::Center,
|
||||
None => sym::Unknown,
|
||||
},
|
||||
);
|
||||
// This needs to match `FlagV1` in library/core/src/fmt/mod.rs.
|
||||
let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
|
||||
| ((sign == Some(FormatSign::Minus)) as u32) << 1
|
||||
| (alternate as u32) << 2
|
||||
| (zero_pad as u32) << 3
|
||||
| ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4
|
||||
| ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5;
|
||||
let flags = ctx.expr_u32(sp, flags);
|
||||
let precision = make_count(ctx, sp, &precision, argmap);
|
||||
let width = make_count(ctx, sp, &width, argmap);
|
||||
let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
sp,
|
||||
hir::LangItem::FormatPlaceholder,
|
||||
sym::new,
|
||||
));
|
||||
let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]);
|
||||
ctx.expr_call_mut(sp, format_placeholder_new, args)
|
||||
}
|
||||
|
||||
fn expand_format_args<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
macsp: Span,
|
||||
fmt: &FormatArgs,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let lit_pieces =
|
||||
ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {
|
||||
match piece {
|
||||
&FormatArgsPiece::Literal(s) => Some(ctx.expr_str(fmt.span, s)),
|
||||
&FormatArgsPiece::Placeholder(_) => {
|
||||
// Inject empty string before placeholders when not already preceded by a literal piece.
|
||||
if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
|
||||
Some(ctx.expr_str(fmt.span, kw::Empty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
let lit_pieces = ctx.expr_array_ref(fmt.span, lit_pieces);
|
||||
|
||||
// Whether we'll use the `Arguments::new_v1_formatted` form (true),
|
||||
// or the `Arguments::new_v1` form (false).
|
||||
let mut use_format_options = false;
|
||||
|
||||
// Create a list of all _unique_ (argument, format trait) combinations.
|
||||
// E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
|
||||
let mut argmap = FxIndexSet::default();
|
||||
for piece in &fmt.template {
|
||||
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
|
||||
if placeholder.format_options != Default::default() {
|
||||
// Can't use basic form if there's any formatting options.
|
||||
use_format_options = true;
|
||||
}
|
||||
if let Ok(index) = placeholder.argument.index {
|
||||
if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
|
||||
// Duplicate (argument, format trait) combination,
|
||||
// which we'll only put once in the args array.
|
||||
use_format_options = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let format_options = use_format_options.then(|| {
|
||||
// Generate:
|
||||
// &[format_spec_0, format_spec_1, format_spec_2]
|
||||
let elements: Vec<_> = fmt
|
||||
.template
|
||||
.iter()
|
||||
.filter_map(|piece| {
|
||||
let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
|
||||
Some(make_format_spec(ctx, macsp, placeholder, &mut argmap))
|
||||
})
|
||||
.collect();
|
||||
ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements))
|
||||
});
|
||||
|
||||
let arguments = fmt.arguments.all_args();
|
||||
|
||||
// If the args array contains exactly all the original arguments once,
|
||||
// in order, we can use a simple array instead of a `match` construction.
|
||||
// However, if there's a yield point in any argument except the first one,
|
||||
// we don't do this, because an ArgumentV1 cannot be kept across yield points.
|
||||
//
|
||||
// This is an optimization, speeding up compilation about 1-2% in some cases.
|
||||
// See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609
|
||||
let use_simple_array = argmap.len() == arguments.len()
|
||||
&& argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
|
||||
&& arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
|
||||
|
||||
let args = if use_simple_array {
|
||||
// Generate:
|
||||
// &[
|
||||
// <core::fmt::ArgumentV1>::new_display(&arg0),
|
||||
// <core::fmt::ArgumentV1>::new_lower_hex(&arg1),
|
||||
// <core::fmt::ArgumentV1>::new_debug(&arg2),
|
||||
// …
|
||||
// ]
|
||||
let elements: Vec<_> = arguments
|
||||
.iter()
|
||||
.zip(argmap)
|
||||
.map(|(arg, (_, ty))| {
|
||||
let sp = arg.expr.span.with_ctxt(macsp.ctxt());
|
||||
let arg = ctx.lower_expr(&arg.expr);
|
||||
let ref_arg = ctx.arena.alloc(ctx.expr(
|
||||
sp,
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg),
|
||||
));
|
||||
make_argument(ctx, sp, ref_arg, ty)
|
||||
})
|
||||
.collect();
|
||||
ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements))
|
||||
} else {
|
||||
// Generate:
|
||||
// &match (&arg0, &arg1, &…) {
|
||||
// args => [
|
||||
// <core::fmt::ArgumentV1>::new_display(args.0),
|
||||
// <core::fmt::ArgumentV1>::new_lower_hex(args.1),
|
||||
// <core::fmt::ArgumentV1>::new_debug(args.0),
|
||||
// …
|
||||
// ]
|
||||
// }
|
||||
let args_ident = Ident::new(sym::args, macsp);
|
||||
let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
|
||||
let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| {
|
||||
if let Some(arg) = arguments.get(arg_index) {
|
||||
let sp = arg.expr.span.with_ctxt(macsp.ctxt());
|
||||
let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id);
|
||||
let arg = ctx.arena.alloc(ctx.expr(
|
||||
sp,
|
||||
hir::ExprKind::Field(
|
||||
args_ident_expr,
|
||||
Ident::new(sym::integer(arg_index), macsp),
|
||||
),
|
||||
));
|
||||
make_argument(ctx, sp, arg, ty)
|
||||
} else {
|
||||
ctx.expr(macsp, hir::ExprKind::Err)
|
||||
}
|
||||
}));
|
||||
let elements: Vec<_> = arguments
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
let arg_expr = ctx.lower_expr(&arg.expr);
|
||||
ctx.expr(
|
||||
arg.expr.span.with_ctxt(macsp.ctxt()),
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let args_tuple = ctx
|
||||
.arena
|
||||
.alloc(ctx.expr(macsp, hir::ExprKind::Tup(ctx.arena.alloc_from_iter(elements))));
|
||||
let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
|
||||
let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]);
|
||||
let match_expr = ctx.arena.alloc(ctx.expr_match(
|
||||
macsp,
|
||||
args_tuple,
|
||||
match_arms,
|
||||
hir::MatchSource::FormatArgs,
|
||||
));
|
||||
ctx.expr(
|
||||
macsp,
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr),
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(format_options) = format_options {
|
||||
// Generate:
|
||||
// <core::fmt::Arguments>::new_v1_formatted(
|
||||
// lit_pieces,
|
||||
// args,
|
||||
// format_options,
|
||||
// unsafe { ::core::fmt::UnsafeArg::new() }
|
||||
// )
|
||||
let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatArguments,
|
||||
sym::new_v1_formatted,
|
||||
));
|
||||
let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatUnsafeArg,
|
||||
sym::new,
|
||||
));
|
||||
let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]);
|
||||
let hir_id = ctx.next_id();
|
||||
let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(unsafe_arg_new_call),
|
||||
hir_id,
|
||||
rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
|
||||
span: macsp,
|
||||
targeted_by_break: false,
|
||||
}));
|
||||
let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]);
|
||||
hir::ExprKind::Call(new_v1_formatted, args)
|
||||
} else {
|
||||
// Generate:
|
||||
// <core::fmt::Arguments>::new_v1(
|
||||
// lit_pieces,
|
||||
// args,
|
||||
// )
|
||||
let new_v1 = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatArguments,
|
||||
sym::new_v1,
|
||||
));
|
||||
let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]);
|
||||
hir::ExprKind::Call(new_v1, new_args)
|
||||
}
|
||||
}
|
||||
|
||||
fn may_contain_yield_point(e: &ast::Expr) -> bool {
|
||||
struct MayContainYieldPoint(bool);
|
||||
|
||||
impl Visitor<'_> for MayContainYieldPoint {
|
||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
||||
if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
|
||||
self.0 = true;
|
||||
} else {
|
||||
visit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mac_call(&mut self, _: &ast::MacCall) {
|
||||
// Macros should be expanded at this point.
|
||||
unreachable!("unexpanded macro in ast lowering");
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, _: &ast::Item) {
|
||||
// Do not recurse into nested items.
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = MayContainYieldPoint(false);
|
||||
visitor.visit_expr(e);
|
||||
visitor.0
|
||||
}
|
||||
|
|
@ -275,19 +275,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_fn(
|
||||
&mut self,
|
||||
fk: intravisit::FnKind<'hir>,
|
||||
fd: &'hir FnDecl<'hir>,
|
||||
b: BodyId,
|
||||
_: Span,
|
||||
id: HirId,
|
||||
) {
|
||||
assert_eq!(self.owner, id.owner);
|
||||
assert_eq!(self.parent_node, id.local_id);
|
||||
intravisit::walk_fn(self, fk, fd, b, id);
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &'hir Block<'hir>) {
|
||||
self.insert(block.span, block.hir_id, Node::Block(block));
|
||||
self.with_parent(block.hir_id, |this| {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
current_hir_id_owner: hir::CRATE_OWNER_ID,
|
||||
item_local_id_counter: hir::ItemLocalId::new(0),
|
||||
node_id_to_local_id: Default::default(),
|
||||
local_id_to_def_id: SortedMap::new(),
|
||||
trait_map: Default::default(),
|
||||
|
||||
// Lowering state.
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ mod asm;
|
|||
mod block;
|
||||
mod errors;
|
||||
mod expr;
|
||||
mod format;
|
||||
mod index;
|
||||
mod item;
|
||||
mod lifetime_collector;
|
||||
|
|
@ -118,7 +119,6 @@ struct LoweringContext<'a, 'hir> {
|
|||
|
||||
current_hir_id_owner: hir::OwnerId,
|
||||
item_local_id_counter: hir::ItemLocalId,
|
||||
local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
|
||||
trait_map: FxHashMap<ItemLocalId, Box<[TraitCandidate]>>,
|
||||
|
||||
impl_trait_defs: Vec<hir::GenericParam<'hir>>,
|
||||
|
|
@ -416,6 +416,7 @@ fn compute_hir_hash(
|
|||
|
||||
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
let sess = tcx.sess;
|
||||
tcx.ensure().output_filenames(());
|
||||
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
|
||||
|
||||
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
|
||||
|
|
@ -565,7 +566,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let current_attrs = std::mem::take(&mut self.attrs);
|
||||
let current_bodies = std::mem::take(&mut self.bodies);
|
||||
let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
|
||||
let current_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
|
||||
let current_trait_map = std::mem::take(&mut self.trait_map);
|
||||
let current_owner =
|
||||
std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id });
|
||||
|
|
@ -592,7 +592,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.attrs = current_attrs;
|
||||
self.bodies = current_bodies;
|
||||
self.node_id_to_local_id = current_node_ids;
|
||||
self.local_id_to_def_id = current_id_to_def_id;
|
||||
self.trait_map = current_trait_map;
|
||||
self.current_hir_id_owner = current_owner;
|
||||
self.item_local_id_counter = current_local_counter;
|
||||
|
|
@ -627,7 +626,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
|
||||
let attrs = std::mem::take(&mut self.attrs);
|
||||
let mut bodies = std::mem::take(&mut self.bodies);
|
||||
let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
|
||||
let trait_map = std::mem::take(&mut self.trait_map);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
@ -643,13 +641,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
|
||||
let (nodes, parenting) =
|
||||
index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies);
|
||||
let nodes = hir::OwnerNodes {
|
||||
hash_including_bodies,
|
||||
hash_without_bodies,
|
||||
nodes,
|
||||
bodies,
|
||||
local_id_to_def_id,
|
||||
};
|
||||
let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies };
|
||||
let attrs = {
|
||||
let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
|
|
@ -708,7 +700,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
assert_ne!(local_id, hir::ItemLocalId::new(0));
|
||||
if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
|
||||
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
self.local_id_to_def_id.insert(local_id, def_id);
|
||||
}
|
||||
|
||||
if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) {
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@ edition = "2021"
|
|||
[lib]
|
||||
|
||||
[dependencies]
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_parse_format = { path = "../rustc_parse_format" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ use rustc_ast::token;
|
|||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, AssocOp, Fixity};
|
||||
use rustc_ast::{self as ast, BlockCheckMode};
|
||||
use rustc_ast::{
|
||||
FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign,
|
||||
FormatTrait,
|
||||
};
|
||||
use std::fmt::Write;
|
||||
|
||||
impl<'a> State<'a> {
|
||||
fn print_else(&mut self, els: Option<&ast::Expr>) {
|
||||
|
|
@ -527,9 +532,23 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
ast::ExprKind::InlineAsm(a) => {
|
||||
// FIXME: This should have its own syntax, distinct from a macro invocation.
|
||||
self.word("asm!");
|
||||
self.print_inline_asm(a);
|
||||
}
|
||||
ast::ExprKind::FormatArgs(fmt) => {
|
||||
// FIXME: This should have its own syntax, distinct from a macro invocation.
|
||||
self.word("format_args!");
|
||||
self.popen();
|
||||
self.rbox(0, Inconsistent);
|
||||
self.word(reconstruct_format_args_template_string(&fmt.template));
|
||||
for arg in fmt.arguments.all_args() {
|
||||
self.word_space(",");
|
||||
self.print_expr(&arg.expr);
|
||||
}
|
||||
self.end();
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::MacCall(m) => self.print_mac(m),
|
||||
ast::ExprKind::Paren(e) => {
|
||||
self.popen();
|
||||
|
|
@ -629,3 +648,88 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String {
|
||||
let mut template = "\"".to_string();
|
||||
for piece in pieces {
|
||||
match piece {
|
||||
FormatArgsPiece::Literal(s) => {
|
||||
for c in s.as_str().escape_debug() {
|
||||
template.push(c);
|
||||
if let '{' | '}' = c {
|
||||
template.push(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
FormatArgsPiece::Placeholder(p) => {
|
||||
template.push('{');
|
||||
let (Ok(n) | Err(n)) = p.argument.index;
|
||||
write!(template, "{n}").unwrap();
|
||||
if p.format_options != Default::default() || p.format_trait != FormatTrait::Display
|
||||
{
|
||||
template.push_str(":");
|
||||
}
|
||||
if let Some(fill) = p.format_options.fill {
|
||||
template.push(fill);
|
||||
}
|
||||
match p.format_options.alignment {
|
||||
Some(FormatAlignment::Left) => template.push_str("<"),
|
||||
Some(FormatAlignment::Right) => template.push_str(">"),
|
||||
Some(FormatAlignment::Center) => template.push_str("^"),
|
||||
None => {}
|
||||
}
|
||||
match p.format_options.sign {
|
||||
Some(FormatSign::Plus) => template.push('+'),
|
||||
Some(FormatSign::Minus) => template.push('-'),
|
||||
None => {}
|
||||
}
|
||||
if p.format_options.alternate {
|
||||
template.push('#');
|
||||
}
|
||||
if p.format_options.zero_pad {
|
||||
template.push('0');
|
||||
}
|
||||
if let Some(width) = &p.format_options.width {
|
||||
match width {
|
||||
FormatCount::Literal(n) => write!(template, "{n}").unwrap(),
|
||||
FormatCount::Argument(FormatArgPosition {
|
||||
index: Ok(n) | Err(n), ..
|
||||
}) => {
|
||||
write!(template, "{n}$").unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(precision) = &p.format_options.precision {
|
||||
template.push('.');
|
||||
match precision {
|
||||
FormatCount::Literal(n) => write!(template, "{n}").unwrap(),
|
||||
FormatCount::Argument(FormatArgPosition {
|
||||
index: Ok(n) | Err(n), ..
|
||||
}) => {
|
||||
write!(template, "{n}$").unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
match p.format_options.debug_hex {
|
||||
Some(FormatDebugHex::Lower) => template.push('x'),
|
||||
Some(FormatDebugHex::Upper) => template.push('X'),
|
||||
None => {}
|
||||
}
|
||||
template.push_str(match p.format_trait {
|
||||
FormatTrait::Display => "",
|
||||
FormatTrait::Debug => "?",
|
||||
FormatTrait::LowerExp => "e",
|
||||
FormatTrait::UpperExp => "E",
|
||||
FormatTrait::Octal => "o",
|
||||
FormatTrait::Pointer => "p",
|
||||
FormatTrait::Binary => "b",
|
||||
FormatTrait::LowerHex => "x",
|
||||
FormatTrait::UpperHex => "X",
|
||||
});
|
||||
template.push('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
template.push('"');
|
||||
template
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
desc,
|
||||
);
|
||||
|
||||
err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_desc));
|
||||
err.span_label(borrow_span, format!("{} is borrowed here", borrow_desc));
|
||||
err.span_label(span, format!("use of borrowed {}", borrow_desc));
|
||||
err
|
||||
}
|
||||
|
|
@ -250,8 +250,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
|
|||
desc,
|
||||
);
|
||||
|
||||
err.span_label(borrow_span, format!("borrow of {} occurs here", desc));
|
||||
err.span_label(span, format!("assignment to borrowed {} occurs here", desc));
|
||||
err.span_label(borrow_span, format!("{} is borrowed here", desc));
|
||||
err.span_label(span, format!("{} is assigned to here but it was already borrowed", desc));
|
||||
err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -393,6 +393,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
| mir::StatementKind::AscribeUserType(..)
|
||||
| mir::StatementKind::Coverage(..)
|
||||
| mir::StatementKind::Intrinsic(..)
|
||||
| mir::StatementKind::ConstEvalCounter
|
||||
| mir::StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -766,7 +766,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
let copy_did = infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
|
||||
let cause = ObligationCause::new(
|
||||
span,
|
||||
self.mir_hir_id(),
|
||||
self.mir_def_id(),
|
||||
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
||||
);
|
||||
let errors = rustc_trait_selection::traits::fully_solve_bound(
|
||||
|
|
@ -1736,7 +1736,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
None,
|
||||
Some(borrow_span),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
|
@ -2599,7 +2599,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
match ty.kind() {
|
||||
ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
|
||||
self.mir_def_id(),
|
||||
self.infcx.tcx.fn_sig(self.mir_def_id()),
|
||||
self.infcx.tcx.fn_sig(self.mir_def_id()).subst_identity(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
//! Print diagnostics to explain why values are borrowed.
|
||||
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::mir::{
|
||||
|
|
@ -11,6 +13,7 @@ use rustc_middle::ty::adjustment::PointerCast;
|
|||
use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::{sym, DesugaringKind, Span};
|
||||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
|
||||
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
|
||||
use crate::{
|
||||
|
|
@ -63,6 +66,36 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
borrow_span: Option<Span>,
|
||||
multiple_borrow_span: Option<(Span, Span)>,
|
||||
) {
|
||||
if let Some(span) = borrow_span {
|
||||
let def_id = body.source.def_id();
|
||||
if let Some(node) = tcx.hir().get_if_local(def_id)
|
||||
&& let Some(body_id) = node.body_id()
|
||||
{
|
||||
let body = tcx.hir().body(body_id);
|
||||
let mut expr_finder = FindExprBySpan::new(span);
|
||||
expr_finder.visit_expr(body.value);
|
||||
if let Some(mut expr) = expr_finder.result {
|
||||
while let hir::ExprKind::AddrOf(_, _, inner)
|
||||
| hir::ExprKind::Unary(hir::UnOp::Deref, inner)
|
||||
| hir::ExprKind::Field(inner, _)
|
||||
| hir::ExprKind::MethodCall(_, inner, _, _)
|
||||
| hir::ExprKind::Index(inner, _) = &expr.kind
|
||||
{
|
||||
expr = inner;
|
||||
}
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind
|
||||
&& let [hir::PathSegment { ident, args: None, .. }] = p.segments
|
||||
&& let hir::def::Res::Local(hir_id) = p.res
|
||||
&& let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id)
|
||||
{
|
||||
err.span_label(
|
||||
pat.span,
|
||||
&format!("binding `{ident}` declared here"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
match *self {
|
||||
BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
|
||||
let message = match later_use_kind {
|
||||
|
|
|
|||
|
|
@ -1064,7 +1064,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
CallKind::Normal { self_arg, desugaring, method_did } => {
|
||||
CallKind::Normal { self_arg, desugaring, method_did, method_substs } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
let tcx = self.infcx.tcx;
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
|
|
@ -1128,15 +1128,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"{place_name} {partially_str}moved due to this method call{loop_message}",
|
||||
),
|
||||
);
|
||||
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
// Erase and shadow everything that could be passed to the new infcx.
|
||||
let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
|
||||
let method_substs = tcx.erase_regions(method_substs);
|
||||
|
||||
if let ty::Adt(def, substs) = ty.kind()
|
||||
&& Some(def.did()) == tcx.lang_items().pin_type()
|
||||
&& let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
|
||||
&& let self_ty = infcx.replace_bound_vars_with_fresh_vars(
|
||||
fn_call_span,
|
||||
LateBoundRegionConversionTime::FnCall,
|
||||
tcx.fn_sig(method_did).input(0),
|
||||
tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
|
||||
)
|
||||
&& infcx.can_eq(self.param_env, ty, self_ty).is_ok()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
};
|
||||
self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
|
||||
|
||||
use_spans.args_span_label(err, format!("move out of {place_desc} occurs here"));
|
||||
use_spans.args_span_label(err, format!("{place_desc} is moved here"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -813,17 +813,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
if *outlived_f != ty::ReStatic {
|
||||
return;
|
||||
}
|
||||
let suitable_region = self.infcx.tcx.is_suitable_region(f);
|
||||
let Some(suitable_region) = suitable_region else { return; };
|
||||
|
||||
let fn_returns = self
|
||||
.infcx
|
||||
.tcx
|
||||
.is_suitable_region(f)
|
||||
.map(|r| self.infcx.tcx.return_type_impl_or_dyn_traits(r.def_id))
|
||||
.unwrap_or_default();
|
||||
|
||||
if fn_returns.is_empty() {
|
||||
return;
|
||||
}
|
||||
let fn_returns = self.infcx.tcx.return_type_impl_or_dyn_traits(suitable_region.def_id);
|
||||
|
||||
let param = if let Some(param) = find_param_with_region(self.infcx.tcx, f, outlived_f) {
|
||||
param
|
||||
|
|
@ -839,15 +832,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
};
|
||||
let captures = format!("captures data from {arg}");
|
||||
|
||||
return nice_region_error::suggest_new_region_bound(
|
||||
self.infcx.tcx,
|
||||
diag,
|
||||
fn_returns,
|
||||
lifetime.to_string(),
|
||||
Some(arg),
|
||||
captures,
|
||||
Some((param.param_ty_span, param.param_ty.to_string())),
|
||||
self.infcx.tcx.is_suitable_region(f).map(|r| r.def_id),
|
||||
if !fn_returns.is_empty() {
|
||||
nice_region_error::suggest_new_region_bound(
|
||||
self.infcx.tcx,
|
||||
diag,
|
||||
fn_returns,
|
||||
lifetime.to_string(),
|
||||
Some(arg),
|
||||
captures,
|
||||
Some((param.param_ty_span, param.param_ty.to_string())),
|
||||
Some(suitable_region.def_id),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let Some((alias_tys, alias_span)) = self
|
||||
.infcx
|
||||
.tcx
|
||||
.return_type_impl_or_dyn_traits_with_type_alias(suitable_region.def_id) else { return; };
|
||||
|
||||
// in case the return type of the method is a type alias
|
||||
let mut spans_suggs: Vec<_> = Vec::new();
|
||||
for alias_ty in alias_tys {
|
||||
if alias_ty.span.desugaring_kind().is_some() {
|
||||
// Skip `async` desugaring `impl Future`.
|
||||
()
|
||||
}
|
||||
if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
|
||||
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
|
||||
}
|
||||
}
|
||||
spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string()));
|
||||
diag.multipart_suggestion_verbose(
|
||||
&format!(
|
||||
"to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias"
|
||||
),
|
||||
spans_suggs,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
LocalMutationIsAllowed::Yes,
|
||||
);
|
||||
}
|
||||
StatementKind::Nop
|
||||
StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::Deinit(..)
|
||||
| StatementKind::SetDiscriminant { .. } => {
|
||||
|
|
|
|||
|
|
@ -609,7 +609,8 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
|||
StatementKind::AscribeUserType(..)
|
||||
// Doesn't have any language semantics
|
||||
| StatementKind::Coverage(..)
|
||||
// Does not actually affect borrowck
|
||||
// These do not actually affect borrowck
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::StorageLive(..) => {}
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.access_place(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
|||
use rustc_data_structures::graph::scc::Sccs;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::outlives::test_type_match;
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
|
||||
|
|
@ -2022,7 +2021,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
.map(|constraint| BlameConstraint {
|
||||
category: constraint.category,
|
||||
from_closure: constraint.from_closure,
|
||||
cause: ObligationCause::new(constraint.span, CRATE_HIR_ID, cause_code.clone()),
|
||||
cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()),
|
||||
variance_info: constraint.variance_info,
|
||||
outlives_constraint: *constraint,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -273,7 +273,6 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
// This logic duplicates most of `check_opaque_meets_bounds`.
|
||||
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
|
||||
let param_env = self.tcx.param_env(def_id);
|
||||
let body_id = self.tcx.local_def_id_to_hir_id(def_id);
|
||||
// HACK This bubble is required for this tests to pass:
|
||||
// type-alias-impl-trait/issue-67844-nested-opaque.rs
|
||||
let infcx =
|
||||
|
|
@ -290,7 +289,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
// the bounds that the function supplies.
|
||||
let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
|
||||
if let Err(err) = ocx.eq(
|
||||
&ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
&ObligationCause::misc(instantiated_ty.span, def_id),
|
||||
param_env,
|
||||
opaque_ty,
|
||||
definition_ty,
|
||||
|
|
@ -298,7 +297,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
infcx
|
||||
.err_ctxt()
|
||||
.report_mismatched_types(
|
||||
&ObligationCause::misc(instantiated_ty.span, body_id),
|
||||
&ObligationCause::misc(instantiated_ty.span, def_id),
|
||||
opaque_ty,
|
||||
definition_ty,
|
||||
err,
|
||||
|
|
@ -309,7 +308,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
ocx.register_obligation(Obligation::misc(
|
||||
infcx.tcx,
|
||||
instantiated_ty.span,
|
||||
body_id,
|
||||
def_id,
|
||||
param_env,
|
||||
predicate,
|
||||
));
|
||||
|
|
@ -368,18 +367,6 @@ fn check_opaque_type_parameter_valid(
|
|||
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
|
||||
let arg_is_param = match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
|
||||
GenericArgKind::Lifetime(lt) if lt.is_static() => {
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_label(
|
||||
tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
|
||||
"cannot use static lifetime; use a bound lifetime \
|
||||
instead or remove the lifetime parameter from the \
|
||||
opaque type",
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1258,6 +1258,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
| StatementKind::StorageDead(..)
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop => {}
|
||||
StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
|
||||
bug!("Statement not allowed in this MIR phase")
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
// C-variadic fns also have a `VaList` input that's not listed in the signature
|
||||
// (as it's created inside the body itself, not passed in from outside).
|
||||
if let DefiningTy::FnDef(def_id, _) = defining_ty {
|
||||
if self.infcx.tcx.fn_sig(def_id).c_variadic() {
|
||||
if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
|
||||
let va_list_did = self.infcx.tcx.require_lang_item(
|
||||
LangItem::VaList,
|
||||
Some(self.infcx.tcx.def_span(self.mir_def.did)),
|
||||
|
|
@ -665,7 +665,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
DefiningTy::FnDef(def_id, _) => {
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
let sig = tcx.fn_sig(def_id).subst_identity();
|
||||
let sig = indices.fold_to_region_vids(tcx, sig);
|
||||
sig.inputs_and_output()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
| ExprKind::Continue(_)
|
||||
| ExprKind::Err
|
||||
| ExprKind::Field(_, _)
|
||||
| ExprKind::FormatArgs(_)
|
||||
| ExprKind::ForLoop(_, _, _, _)
|
||||
| ExprKind::If(_, _, _)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ pub fn expand_deriving_copy(
|
|||
span,
|
||||
path: path_std!(marker::Copy),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: false,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: true,
|
||||
methods: Vec::new(),
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ pub fn expand_deriving_clone(
|
|||
span,
|
||||
path: path_std!(clone::Clone),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: bounds,
|
||||
supports_unions: true,
|
||||
methods: vec![MethodDef {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ pub fn expand_deriving_eq(
|
|||
span,
|
||||
path: path_std!(cmp::Eq),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: true,
|
||||
methods: vec![MethodDef {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ pub fn expand_deriving_ord(
|
|||
span,
|
||||
path: path_std!(cmp::Ord),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ pub fn expand_deriving_partial_eq(
|
|||
span,
|
||||
path: path_std!(cmp::PartialEq),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::deriving::generic::ty::*;
|
||||
use crate::deriving::generic::*;
|
||||
use crate::deriving::{path_std, pathvec_std};
|
||||
use rustc_ast::MetaItem;
|
||||
use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
|
|
@ -21,6 +21,27 @@ pub fn expand_deriving_partial_ord(
|
|||
|
||||
let attrs = thin_vec![cx.attr_word(sym::inline, span)];
|
||||
|
||||
// Order in which to perform matching
|
||||
let tag_then_data = if let Annotatable::Item(item) = item
|
||||
&& let ItemKind::Enum(def, _) = &item.kind {
|
||||
let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
|
||||
match dataful.iter().filter(|&&b| b).count() {
|
||||
// No data, placing the tag check first makes codegen simpler
|
||||
0 => true,
|
||||
1..=2 => false,
|
||||
_ => {
|
||||
(0..dataful.len()-1).any(|i| {
|
||||
if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) {
|
||||
idx >= 2
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
let partial_cmp_def = MethodDef {
|
||||
name: sym::partial_cmp,
|
||||
generics: Bounds::empty(),
|
||||
|
|
@ -30,7 +51,7 @@ pub fn expand_deriving_partial_ord(
|
|||
attributes: attrs,
|
||||
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
|
||||
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
|
||||
cs_partial_cmp(cx, span, substr)
|
||||
cs_partial_cmp(cx, span, substr, tag_then_data)
|
||||
})),
|
||||
};
|
||||
|
||||
|
|
@ -38,6 +59,7 @@ pub fn expand_deriving_partial_ord(
|
|||
span,
|
||||
path: path_std!(cmp::PartialOrd),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: vec![],
|
||||
supports_unions: false,
|
||||
methods: vec![partial_cmp_def],
|
||||
|
|
@ -47,7 +69,12 @@ pub fn expand_deriving_partial_ord(
|
|||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
||||
pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
|
||||
fn cs_partial_cmp(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
substr: &Substructure<'_>,
|
||||
tag_then_data: bool,
|
||||
) -> BlockOrExpr {
|
||||
let test_id = Ident::new(sym::cmp, span);
|
||||
let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
|
||||
let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
|
||||
|
|
@ -74,12 +101,50 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
|||
let args = vec![field.self_expr.clone(), other_expr.clone()];
|
||||
cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
|
||||
}
|
||||
CsFold::Combine(span, expr1, expr2) => {
|
||||
let eq_arm =
|
||||
cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
|
||||
let neq_arm =
|
||||
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
|
||||
cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
|
||||
CsFold::Combine(span, mut expr1, expr2) => {
|
||||
// When the item is an enum, this expands to
|
||||
// ```
|
||||
// match (expr2) {
|
||||
// Some(Ordering::Equal) => expr1,
|
||||
// cmp => cmp
|
||||
// }
|
||||
// ```
|
||||
// where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match`
|
||||
// against the enum variants. This means that we begin by comparing the enum tags,
|
||||
// before either inspecting their contents (if they match), or returning
|
||||
// the `cmp::Ordering` of comparing the enum tags.
|
||||
// ```
|
||||
// match partial_cmp(self_tag, other_tag) {
|
||||
// Some(Ordering::Equal) => match (self, other) {
|
||||
// (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
|
||||
// (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0),
|
||||
// _ => Some(Ordering::Equal)
|
||||
// }
|
||||
// cmp => cmp
|
||||
// }
|
||||
// ```
|
||||
// If we have any certain enum layouts, flipping this results in better codegen
|
||||
// ```
|
||||
// match (self, other) {
|
||||
// (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
|
||||
// _ => partial_cmp(self_tag, other_tag)
|
||||
// }
|
||||
// ```
|
||||
// Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
|
||||
|
||||
if !tag_then_data
|
||||
&& let ExprKind::Match(_, arms) = &mut expr1.kind
|
||||
&& let Some(last) = arms.last_mut()
|
||||
&& let PatKind::Wild = last.pat.kind {
|
||||
last.body = expr2;
|
||||
expr1
|
||||
} else {
|
||||
let eq_arm =
|
||||
cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
|
||||
let neq_arm =
|
||||
cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
|
||||
cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
|
||||
}
|
||||
}
|
||||
CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ pub fn expand_deriving_debug(
|
|||
span,
|
||||
path: path_std!(fmt::Debug),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ pub fn expand_deriving_rustc_decodable(
|
|||
span,
|
||||
path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ pub fn expand_deriving_default(
|
|||
span,
|
||||
path: Path::new(vec![kw::Default, sym::Default]),
|
||||
skip_path_as_bound: has_a_default_variant(item),
|
||||
needs_copy_as_bound_if_packed: false,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ pub fn expand_deriving_rustc_encodable(
|
|||
span,
|
||||
path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
|
|
|
|||
|
|
@ -165,11 +165,12 @@ pub use SubstructureFields::*;
|
|||
use crate::deriving;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{
|
||||
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind,
|
||||
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
|
||||
Mutability, PatKind, TyKind, VariantData,
|
||||
};
|
||||
use rustc_ast::{GenericArg, GenericParamKind, VariantData};
|
||||
use rustc_attr as attr;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -191,6 +192,9 @@ pub struct TraitDef<'a> {
|
|||
/// Whether to skip adding the current trait as a bound to the type parameters of the type.
|
||||
pub skip_path_as_bound: bool,
|
||||
|
||||
/// Whether `Copy` is needed as an additional bound on type parameters in a packed struct.
|
||||
pub needs_copy_as_bound_if_packed: bool,
|
||||
|
||||
/// Additional bounds required of any type parameters of the type,
|
||||
/// other than the current trait
|
||||
pub additional_bounds: Vec<Ty>,
|
||||
|
|
@ -455,18 +459,6 @@ impl<'a> TraitDef<'a> {
|
|||
}
|
||||
false
|
||||
});
|
||||
let has_no_type_params = match &item.kind {
|
||||
ast::ItemKind::Struct(_, generics)
|
||||
| ast::ItemKind::Enum(_, generics)
|
||||
| ast::ItemKind::Union(_, generics) => !generics
|
||||
.params
|
||||
.iter()
|
||||
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
|
||||
let copy_fields =
|
||||
is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id);
|
||||
|
||||
let newitem = match &item.kind {
|
||||
ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
|
||||
|
|
@ -475,7 +467,7 @@ impl<'a> TraitDef<'a> {
|
|||
item.ident,
|
||||
generics,
|
||||
from_scratch,
|
||||
copy_fields,
|
||||
is_packed,
|
||||
),
|
||||
ast::ItemKind::Enum(enum_def, generics) => {
|
||||
// We ignore `is_packed` here, because `repr(packed)`
|
||||
|
|
@ -493,7 +485,7 @@ impl<'a> TraitDef<'a> {
|
|||
item.ident,
|
||||
generics,
|
||||
from_scratch,
|
||||
copy_fields,
|
||||
is_packed,
|
||||
)
|
||||
} else {
|
||||
cx.span_err(mitem.span, "this trait cannot be derived for unions");
|
||||
|
|
@ -565,6 +557,7 @@ impl<'a> TraitDef<'a> {
|
|||
generics: &Generics,
|
||||
field_tys: Vec<P<ast::Ty>>,
|
||||
methods: Vec<P<ast::AssocItem>>,
|
||||
is_packed: bool,
|
||||
) -> P<ast::Item> {
|
||||
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
|
||||
|
||||
|
|
@ -607,20 +600,32 @@ impl<'a> TraitDef<'a> {
|
|||
.map(|param| match ¶m.kind {
|
||||
GenericParamKind::Lifetime { .. } => param.clone(),
|
||||
GenericParamKind::Type { .. } => {
|
||||
// I don't think this can be moved out of the loop, since
|
||||
// a GenericBound requires an ast id
|
||||
let bounds: Vec<_> =
|
||||
// extra restrictions on the generics parameters to the
|
||||
// type being derived upon
|
||||
self.additional_bounds.iter().map(|p| {
|
||||
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
|
||||
}).chain(
|
||||
// require the current trait
|
||||
self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone()))
|
||||
).chain(
|
||||
// also add in any bounds from the declaration
|
||||
param.bounds.iter().cloned()
|
||||
).collect();
|
||||
// Extra restrictions on the generics parameters to the
|
||||
// type being derived upon.
|
||||
let bounds: Vec<_> = self
|
||||
.additional_bounds
|
||||
.iter()
|
||||
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
|
||||
.chain(
|
||||
// Add a bound for the current trait.
|
||||
self.skip_path_as_bound
|
||||
.not()
|
||||
.then(|| cx.trait_bound(trait_path.clone())),
|
||||
)
|
||||
.chain({
|
||||
// Add a `Copy` bound if required.
|
||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||
let p = deriving::path_std!(marker::Copy);
|
||||
Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.chain(
|
||||
// Also add in any bounds from the declaration.
|
||||
param.bounds.iter().cloned(),
|
||||
)
|
||||
.collect();
|
||||
|
||||
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
|
||||
}
|
||||
|
|
@ -692,9 +697,17 @@ impl<'a> TraitDef<'a> {
|
|||
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
|
||||
.collect();
|
||||
|
||||
// require the current trait
|
||||
// Require the current trait.
|
||||
bounds.push(cx.trait_bound(trait_path.clone()));
|
||||
|
||||
// Add a `Copy` bound if required.
|
||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||
let p = deriving::path_std!(marker::Copy);
|
||||
bounds.push(
|
||||
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)),
|
||||
);
|
||||
}
|
||||
|
||||
let predicate = ast::WhereBoundPredicate {
|
||||
span: self.span,
|
||||
bound_generic_params: field_ty_param.bound_generic_params,
|
||||
|
|
@ -762,7 +775,7 @@ impl<'a> TraitDef<'a> {
|
|||
type_ident: Ident,
|
||||
generics: &Generics,
|
||||
from_scratch: bool,
|
||||
copy_fields: bool,
|
||||
is_packed: bool,
|
||||
) -> P<ast::Item> {
|
||||
let field_tys: Vec<P<ast::Ty>> =
|
||||
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
|
||||
|
|
@ -790,7 +803,7 @@ impl<'a> TraitDef<'a> {
|
|||
type_ident,
|
||||
&selflike_args,
|
||||
&nonselflike_args,
|
||||
copy_fields,
|
||||
is_packed,
|
||||
)
|
||||
};
|
||||
|
||||
|
|
@ -806,7 +819,7 @@ impl<'a> TraitDef<'a> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
|
||||
self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
|
||||
}
|
||||
|
||||
fn expand_enum_def(
|
||||
|
|
@ -861,7 +874,8 @@ impl<'a> TraitDef<'a> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
|
||||
let is_packed = false; // enums are never packed
|
||||
self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1011,8 +1025,8 @@ impl<'a> MethodDef<'a> {
|
|||
/// ```
|
||||
/// But if the struct is `repr(packed)`, we can't use something like
|
||||
/// `&self.x` because that might cause an unaligned ref. So for any trait
|
||||
/// method that takes a reference, if the struct impls `Copy` then we use a
|
||||
/// local block to force a copy:
|
||||
/// method that takes a reference, we use a local block to force a copy.
|
||||
/// This requires that the field impl `Copy`.
|
||||
/// ```
|
||||
/// # struct A { x: u8, y: u8 }
|
||||
/// impl PartialEq for A {
|
||||
|
|
@ -1027,10 +1041,6 @@ impl<'a> MethodDef<'a> {
|
|||
/// ::core::hash::Hash::hash(&{ self.y }, state)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This
|
||||
/// only works if the fields match the alignment required by the
|
||||
/// `packed(N)` attribute. (We'll get errors later on if not.)
|
||||
fn expand_struct_method_body<'b>(
|
||||
&self,
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
|
|
@ -1039,12 +1049,12 @@ impl<'a> MethodDef<'a> {
|
|||
type_ident: Ident,
|
||||
selflike_args: &[P<Expr>],
|
||||
nonselflike_args: &[P<Expr>],
|
||||
copy_fields: bool,
|
||||
is_packed: bool,
|
||||
) -> BlockOrExpr {
|
||||
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
|
||||
|
||||
let selflike_fields =
|
||||
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields);
|
||||
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed);
|
||||
self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
|
|
@ -1514,7 +1524,7 @@ impl<'a> TraitDef<'a> {
|
|||
cx: &mut ExtCtxt<'_>,
|
||||
selflike_args: &[P<Expr>],
|
||||
struct_def: &'a VariantData,
|
||||
copy_fields: bool,
|
||||
is_packed: bool,
|
||||
) -> Vec<FieldInfo> {
|
||||
self.create_fields(struct_def, |i, struct_field, sp| {
|
||||
selflike_args
|
||||
|
|
@ -1533,10 +1543,39 @@ impl<'a> TraitDef<'a> {
|
|||
}),
|
||||
),
|
||||
);
|
||||
if copy_fields {
|
||||
field_expr = cx.expr_block(
|
||||
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
|
||||
);
|
||||
// In general, fields in packed structs are copied via a
|
||||
// block, e.g. `&{self.0}`. The one exception is `[u8]`
|
||||
// fields, which cannot be copied and also never cause
|
||||
// unaligned references. This exception is allowed to
|
||||
// handle the `FlexZeroSlice` type in the `zerovec` crate
|
||||
// within `icu4x-0.9.0`.
|
||||
//
|
||||
// Once use of `icu4x-0.9.0` has dropped sufficiently, this
|
||||
// exception should be removed.
|
||||
let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
|
||||
let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind &&
|
||||
let [seg] = segments.as_slice() &&
|
||||
seg.ident.name == sym::u8 && seg.args.is_none()
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if is_packed {
|
||||
if is_u8_slice {
|
||||
cx.sess.parse_sess.buffer_lint_with_diagnostic(
|
||||
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||
sp,
|
||||
ast::CRATE_NODE_ID,
|
||||
"byte slice in a packed struct that derives a built-in trait",
|
||||
rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive
|
||||
);
|
||||
} else {
|
||||
// Wrap the expression in `{...}`, causing a copy.
|
||||
field_expr = cx.expr_block(
|
||||
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
|
||||
);
|
||||
}
|
||||
}
|
||||
cx.expr_addr_of(sp, field_expr)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ pub fn expand_deriving_hash(
|
|||
span,
|
||||
path,
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods: vec![MethodDef {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::Expr;
|
||||
use rustc_ast::{
|
||||
Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
|
||||
FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount,
|
||||
FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
|
||||
use rustc_expand::base::{self, *};
|
||||
|
|
@ -12,21 +16,15 @@ use rustc_span::{BytePos, InnerSpan, Span};
|
|||
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
|
||||
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
|
||||
|
||||
mod ast;
|
||||
use ast::*;
|
||||
|
||||
mod expand;
|
||||
use expand::expand_parsed_format_args;
|
||||
|
||||
// The format_args!() macro is expanded in three steps:
|
||||
// 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
|
||||
// but doesn't parse the template (the literal) itself.
|
||||
// 2. Second, `make_format_args` will parse the template, the format options, resolve argument references,
|
||||
// produce diagnostics, and turn the whole thing into a `FormatArgs` structure.
|
||||
// 3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure
|
||||
// into the expression that the macro expands to.
|
||||
// produce diagnostics, and turn the whole thing into a `FormatArgs` AST node.
|
||||
// 3. Much later, in AST lowering (rustc_ast_lowering), that `FormatArgs` structure will be turned
|
||||
// into the expression of type `core::fmt::Arguments`.
|
||||
|
||||
// See format/ast.rs for the FormatArgs structure and glossary.
|
||||
// See rustc_ast/src/format.rs for the FormatArgs structure and glossary.
|
||||
|
||||
// Only used in parse_args and report_invalid_references,
|
||||
// to indicate how a referred argument was used.
|
||||
|
|
@ -437,7 +435,16 @@ pub fn make_format_args(
|
|||
format_options: FormatOptions {
|
||||
fill: format.fill,
|
||||
alignment,
|
||||
flags: format.flags,
|
||||
sign: format.sign.map(|s| match s {
|
||||
parse::Sign::Plus => FormatSign::Plus,
|
||||
parse::Sign::Minus => FormatSign::Minus,
|
||||
}),
|
||||
alternate: format.alternate,
|
||||
zero_pad: format.zero_pad,
|
||||
debug_hex: format.debug_hex.map(|s| match s {
|
||||
parse::DebugHex::Lower => FormatDebugHex::Lower,
|
||||
parse::DebugHex::Upper => FormatDebugHex::Upper,
|
||||
}),
|
||||
precision,
|
||||
width,
|
||||
},
|
||||
|
|
@ -850,7 +857,7 @@ fn expand_format_args_impl<'cx>(
|
|||
match parse_args(ecx, sp, tts) {
|
||||
Ok((efmt, args)) => {
|
||||
if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) {
|
||||
MacEager::expr(expand_parsed_format_args(ecx, format_args))
|
||||
MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
|
||||
} else {
|
||||
MacEager::expr(DummyResult::raw_expr(sp, true))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,353 +0,0 @@
|
|||
use super::*;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{BlockCheckMode, UnsafeSource};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_span::{sym, symbol::kw};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
enum ArgumentType {
|
||||
Format(FormatTrait),
|
||||
Usize,
|
||||
}
|
||||
|
||||
fn make_argument(ecx: &ExtCtxt<'_>, sp: Span, arg: P<ast::Expr>, ty: ArgumentType) -> P<ast::Expr> {
|
||||
// Generate:
|
||||
// ::core::fmt::ArgumentV1::new_…(arg)
|
||||
use ArgumentType::*;
|
||||
use FormatTrait::*;
|
||||
ecx.expr_call_global(
|
||||
sp,
|
||||
ecx.std_path(&[
|
||||
sym::fmt,
|
||||
sym::ArgumentV1,
|
||||
match ty {
|
||||
Format(Display) => sym::new_display,
|
||||
Format(Debug) => sym::new_debug,
|
||||
Format(LowerExp) => sym::new_lower_exp,
|
||||
Format(UpperExp) => sym::new_upper_exp,
|
||||
Format(Octal) => sym::new_octal,
|
||||
Format(Pointer) => sym::new_pointer,
|
||||
Format(Binary) => sym::new_binary,
|
||||
Format(LowerHex) => sym::new_lower_hex,
|
||||
Format(UpperHex) => sym::new_upper_hex,
|
||||
Usize => sym::from_usize,
|
||||
},
|
||||
]),
|
||||
vec![arg],
|
||||
)
|
||||
}
|
||||
|
||||
fn make_count(
|
||||
ecx: &ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
count: &Option<FormatCount>,
|
||||
argmap: &mut FxIndexSet<(usize, ArgumentType)>,
|
||||
) -> P<ast::Expr> {
|
||||
// Generate:
|
||||
// ::core::fmt::rt::v1::Count::…(…)
|
||||
match count {
|
||||
Some(FormatCount::Literal(n)) => ecx.expr_call_global(
|
||||
sp,
|
||||
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Is]),
|
||||
vec![ecx.expr_usize(sp, *n)],
|
||||
),
|
||||
Some(FormatCount::Argument(arg)) => {
|
||||
if let Ok(arg_index) = arg.index {
|
||||
let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
|
||||
ecx.expr_call_global(
|
||||
sp,
|
||||
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Param]),
|
||||
vec![ecx.expr_usize(sp, i)],
|
||||
)
|
||||
} else {
|
||||
DummyResult::raw_expr(sp, true)
|
||||
}
|
||||
}
|
||||
None => ecx.expr_path(ecx.path_global(
|
||||
sp,
|
||||
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Implied]),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_format_spec(
|
||||
ecx: &ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
placeholder: &FormatPlaceholder,
|
||||
argmap: &mut FxIndexSet<(usize, ArgumentType)>,
|
||||
) -> P<ast::Expr> {
|
||||
// Generate:
|
||||
// ::core::fmt::rt::v1::Argument {
|
||||
// position: 0usize,
|
||||
// format: ::core::fmt::rt::v1::FormatSpec {
|
||||
// fill: ' ',
|
||||
// align: ::core::fmt::rt::v1::Alignment::Unknown,
|
||||
// flags: 0u32,
|
||||
// precision: ::core::fmt::rt::v1::Count::Implied,
|
||||
// width: ::core::fmt::rt::v1::Count::Implied,
|
||||
// },
|
||||
// }
|
||||
let position = match placeholder.argument.index {
|
||||
Ok(arg_index) => {
|
||||
let (i, _) =
|
||||
argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
|
||||
ecx.expr_usize(sp, i)
|
||||
}
|
||||
Err(_) => DummyResult::raw_expr(sp, true),
|
||||
};
|
||||
let fill = ecx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' '));
|
||||
let align = ecx.expr_path(ecx.path_global(
|
||||
sp,
|
||||
ecx.std_path(&[
|
||||
sym::fmt,
|
||||
sym::rt,
|
||||
sym::v1,
|
||||
sym::Alignment,
|
||||
match placeholder.format_options.alignment {
|
||||
Some(FormatAlignment::Left) => sym::Left,
|
||||
Some(FormatAlignment::Right) => sym::Right,
|
||||
Some(FormatAlignment::Center) => sym::Center,
|
||||
None => sym::Unknown,
|
||||
},
|
||||
]),
|
||||
));
|
||||
let flags = ecx.expr_u32(sp, placeholder.format_options.flags);
|
||||
let prec = make_count(ecx, sp, &placeholder.format_options.precision, argmap);
|
||||
let width = make_count(ecx, sp, &placeholder.format_options.width, argmap);
|
||||
ecx.expr_struct(
|
||||
sp,
|
||||
ecx.path_global(sp, ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Argument])),
|
||||
vec![
|
||||
ecx.field_imm(sp, Ident::new(sym::position, sp), position),
|
||||
ecx.field_imm(
|
||||
sp,
|
||||
Ident::new(sym::format, sp),
|
||||
ecx.expr_struct(
|
||||
sp,
|
||||
ecx.path_global(
|
||||
sp,
|
||||
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::FormatSpec]),
|
||||
),
|
||||
vec![
|
||||
ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
|
||||
ecx.field_imm(sp, Ident::new(sym::align, sp), align),
|
||||
ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
|
||||
ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
|
||||
ecx.field_imm(sp, Ident::new(sym::width, sp), width),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> {
|
||||
let macsp = ecx.with_def_site_ctxt(ecx.call_site());
|
||||
|
||||
let lit_pieces = ecx.expr_array_ref(
|
||||
fmt.span,
|
||||
fmt.template
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, piece)| match piece {
|
||||
&FormatArgsPiece::Literal(s) => Some(ecx.expr_str(fmt.span, s)),
|
||||
&FormatArgsPiece::Placeholder(_) => {
|
||||
// Inject empty string before placeholders when not already preceded by a literal piece.
|
||||
if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
|
||||
Some(ecx.expr_str(fmt.span, kw::Empty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// Whether we'll use the `Arguments::new_v1_formatted` form (true),
|
||||
// or the `Arguments::new_v1` form (false).
|
||||
let mut use_format_options = false;
|
||||
|
||||
// Create a list of all _unique_ (argument, format trait) combinations.
|
||||
// E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
|
||||
let mut argmap = FxIndexSet::default();
|
||||
for piece in &fmt.template {
|
||||
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
|
||||
if placeholder.format_options != Default::default() {
|
||||
// Can't use basic form if there's any formatting options.
|
||||
use_format_options = true;
|
||||
}
|
||||
if let Ok(index) = placeholder.argument.index {
|
||||
if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
|
||||
// Duplicate (argument, format trait) combination,
|
||||
// which we'll only put once in the args array.
|
||||
use_format_options = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let format_options = use_format_options.then(|| {
|
||||
// Generate:
|
||||
// &[format_spec_0, format_spec_1, format_spec_2]
|
||||
ecx.expr_array_ref(
|
||||
macsp,
|
||||
fmt.template
|
||||
.iter()
|
||||
.filter_map(|piece| {
|
||||
let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
|
||||
Some(make_format_spec(ecx, macsp, placeholder, &mut argmap))
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
});
|
||||
|
||||
let arguments = fmt.arguments.into_vec();
|
||||
|
||||
// If the args array contains exactly all the original arguments once,
|
||||
// in order, we can use a simple array instead of a `match` construction.
|
||||
// However, if there's a yield point in any argument except the first one,
|
||||
// we don't do this, because an ArgumentV1 cannot be kept across yield points.
|
||||
let use_simple_array = argmap.len() == arguments.len()
|
||||
&& argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
|
||||
&& arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
|
||||
|
||||
let args = if use_simple_array {
|
||||
// Generate:
|
||||
// &[
|
||||
// ::core::fmt::ArgumentV1::new_display(&arg0),
|
||||
// ::core::fmt::ArgumentV1::new_lower_hex(&arg1),
|
||||
// ::core::fmt::ArgumentV1::new_debug(&arg2),
|
||||
// ]
|
||||
ecx.expr_array_ref(
|
||||
macsp,
|
||||
arguments
|
||||
.into_iter()
|
||||
.zip(argmap)
|
||||
.map(|(arg, (_, ty))| {
|
||||
let sp = arg.expr.span.with_ctxt(macsp.ctxt());
|
||||
make_argument(ecx, sp, ecx.expr_addr_of(sp, arg.expr), ty)
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
} else {
|
||||
// Generate:
|
||||
// match (&arg0, &arg1, &arg2) {
|
||||
// args => &[
|
||||
// ::core::fmt::ArgumentV1::new_display(args.0),
|
||||
// ::core::fmt::ArgumentV1::new_lower_hex(args.1),
|
||||
// ::core::fmt::ArgumentV1::new_debug(args.0),
|
||||
// ]
|
||||
// }
|
||||
let args_ident = Ident::new(sym::args, macsp);
|
||||
let args = argmap
|
||||
.iter()
|
||||
.map(|&(arg_index, ty)| {
|
||||
if let Some(arg) = arguments.get(arg_index) {
|
||||
let sp = arg.expr.span.with_ctxt(macsp.ctxt());
|
||||
make_argument(
|
||||
ecx,
|
||||
sp,
|
||||
ecx.expr_field(
|
||||
sp,
|
||||
ecx.expr_ident(macsp, args_ident),
|
||||
Ident::new(sym::integer(arg_index), macsp),
|
||||
),
|
||||
ty,
|
||||
)
|
||||
} else {
|
||||
DummyResult::raw_expr(macsp, true)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
ecx.expr_addr_of(
|
||||
macsp,
|
||||
ecx.expr_match(
|
||||
macsp,
|
||||
ecx.expr_tuple(
|
||||
macsp,
|
||||
arguments
|
||||
.into_iter()
|
||||
.map(|arg| {
|
||||
ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))],
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(format_options) = format_options {
|
||||
// Generate:
|
||||
// ::core::fmt::Arguments::new_v1_formatted(
|
||||
// lit_pieces,
|
||||
// args,
|
||||
// format_options,
|
||||
// unsafe { ::core::fmt::UnsafeArg::new() }
|
||||
// )
|
||||
ecx.expr_call_global(
|
||||
macsp,
|
||||
ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]),
|
||||
vec![
|
||||
lit_pieces,
|
||||
args,
|
||||
format_options,
|
||||
ecx.expr_block(P(ast::Block {
|
||||
stmts: vec![ecx.stmt_expr(ecx.expr_call_global(
|
||||
macsp,
|
||||
ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]),
|
||||
Vec::new(),
|
||||
))],
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
|
||||
span: macsp,
|
||||
tokens: None,
|
||||
could_be_bare_literal: false,
|
||||
})),
|
||||
],
|
||||
)
|
||||
} else {
|
||||
// Generate:
|
||||
// ::core::fmt::Arguments::new_v1(
|
||||
// lit_pieces,
|
||||
// args,
|
||||
// )
|
||||
ecx.expr_call_global(
|
||||
macsp,
|
||||
ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]),
|
||||
vec![lit_pieces, args],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn may_contain_yield_point(e: &ast::Expr) -> bool {
|
||||
struct MayContainYieldPoint(bool);
|
||||
|
||||
impl Visitor<'_> for MayContainYieldPoint {
|
||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
||||
if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
|
||||
self.0 = true;
|
||||
} else {
|
||||
visit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mac_call(&mut self, _: &ast::MacCall) {
|
||||
self.0 = true;
|
||||
}
|
||||
|
||||
fn visit_attribute(&mut self, _: &ast::Attribute) {
|
||||
// Conservatively assume this may be a proc macro attribute in
|
||||
// expression position.
|
||||
self.0 = true;
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, _: &ast::Item) {
|
||||
// Do not recurse into nested items.
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = MayContainYieldPoint(false);
|
||||
visitor.visit_expr(e);
|
||||
visitor.0
|
||||
}
|
||||
|
|
@ -1,13 +1,11 @@
|
|||
task:
|
||||
name: freebsd
|
||||
freebsd_instance:
|
||||
image: freebsd-12-1-release-amd64
|
||||
image: freebsd-13-1-release-amd64
|
||||
setup_rust_script:
|
||||
- pkg install -y curl git bash
|
||||
- curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
- sh rustup.sh --default-toolchain none -y --profile=minimal
|
||||
cargo_bin_cache:
|
||||
folder: ~/.cargo/bin
|
||||
target_cache:
|
||||
folder: target
|
||||
prepare_script:
|
||||
|
|
@ -15,9 +13,4 @@ task:
|
|||
- ./y.rs prepare
|
||||
test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- # Enable backtraces for easier debugging
|
||||
- export RUST_BACKTRACE=1
|
||||
- # Reduce amount of benchmark runs as they are slow
|
||||
- export COMPILE_RUNS=2
|
||||
- export RUN_RUNS=2
|
||||
- ./y.rs test
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -46,36 +50,31 @@ jobs:
|
|||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: s390x-unknown-linux-gnu
|
||||
- os: windows-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-msvc
|
||||
- os: windows-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-cargo-installed-crates
|
||||
|
||||
- name: Cache cargo registry and index
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Set MinGW as the default toolchain
|
||||
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: rustup set default-host x86_64-pc-windows-gnu
|
||||
|
||||
- name: Install MinGW toolchain and wine
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
|
||||
rustup target add x86_64-pc-windows-gnu
|
||||
|
||||
- name: Install AArch64 toolchain and qemu
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
|
||||
|
|
@ -89,6 +88,13 @@ jobs:
|
|||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
|
||||
|
||||
- name: Use sparse cargo registry
|
||||
run: |
|
||||
cat >> ~/.cargo/config.toml <<EOF
|
||||
[unstable]
|
||||
sparse-registry = true
|
||||
EOF
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.rs prepare
|
||||
|
||||
|
|
@ -104,49 +110,47 @@ jobs:
|
|||
- name: Test
|
||||
env:
|
||||
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
|
||||
run: |
|
||||
# Enable backtraces for easier debugging
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
# Reduce amount of benchmark runs as they are slow
|
||||
export COMPILE_RUNS=2
|
||||
export RUN_RUNS=2
|
||||
|
||||
# Enable extra checks
|
||||
export CG_CLIF_ENABLE_VERIFIER=1
|
||||
|
||||
./y.rs test
|
||||
run: ./y.rs test
|
||||
|
||||
- name: Package prebuilt cg_clif
|
||||
run: tar cvfJ cg_clif.tar.xz dist
|
||||
|
||||
- name: Upload prebuilt cg_clif
|
||||
if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
|
||||
uses: actions/upload-artifact@v2
|
||||
if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
|
||||
path: cg_clif.tar.xz
|
||||
|
||||
- name: Upload prebuilt cg_clif (cross compile)
|
||||
if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
|
||||
path: cg_clif.tar.xz
|
||||
|
||||
windows:
|
||||
|
||||
abi_cafe:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 60
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
fail-fast: true
|
||||
matrix:
|
||||
include:
|
||||
# Native Windows build with MSVC
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-unknown-linux-gnu
|
||||
- os: macos-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-apple-darwin
|
||||
- os: windows-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-msvc
|
||||
# cross-compile from Windows to Windows MinGW
|
||||
- os: windows-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
|
|
@ -154,20 +158,6 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-installed-crates
|
||||
|
||||
- name: Cache cargo registry and index
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
|
@ -178,50 +168,20 @@ jobs:
|
|||
if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: rustup set default-host x86_64-pc-windows-gnu
|
||||
|
||||
- name: Prepare dependencies
|
||||
- name: Use sparse cargo registry
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
rustc y.rs -o y.exe -g
|
||||
./y.exe prepare
|
||||
cat >> ~/.cargo/config.toml <<EOF
|
||||
[unstable]
|
||||
sparse-registry = true
|
||||
EOF
|
||||
|
||||
- name: Build without unstable features
|
||||
env:
|
||||
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
|
||||
# This is the config rust-lang/rust uses for builds
|
||||
run: ./y.rs build --no-unstable-features
|
||||
- name: Prepare dependencies
|
||||
run: ./y.rs prepare
|
||||
|
||||
- name: Build
|
||||
run: ./y.rs build --sysroot none
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
# Enable backtraces for easier debugging
|
||||
$Env:RUST_BACKTRACE=1
|
||||
|
||||
# Reduce amount of benchmark runs as they are slow
|
||||
$Env:COMPILE_RUNS=2
|
||||
$Env:RUN_RUNS=2
|
||||
|
||||
# Enable extra checks
|
||||
$Env:CG_CLIF_ENABLE_VERIFIER=1
|
||||
|
||||
# WIP Disable some tests
|
||||
|
||||
# This fails due to some weird argument handling by hyperfine, not an actual regression
|
||||
# more of a build system issue
|
||||
(Get-Content config.txt) -replace '(bench.simple-raytracer)', '# $1' | Out-File config.txt
|
||||
|
||||
# This fails with a different output than expected
|
||||
(Get-Content config.txt) -replace '(test.regex-shootout-regex-dna)', '# $1' | Out-File config.txt
|
||||
|
||||
./y.exe test
|
||||
|
||||
- name: Package prebuilt cg_clif
|
||||
# don't use compression as xzip isn't supported by tar on windows and bzip2 hangs
|
||||
run: tar cvf cg_clif.tar dist
|
||||
|
||||
- name: Upload prebuilt cg_clif
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
|
||||
path: cg_clif.tar
|
||||
- name: Test abi-cafe
|
||||
env:
|
||||
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
|
||||
run: ./y.rs abi-cafe
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
name: Test nightly Cranelift
|
||||
|
||||
on:
|
||||
push:
|
||||
schedule:
|
||||
- cron: '17 1 * * *' # At 01:17 UTC every day.
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ubuntu-latest-cargo-installed-crates
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: |
|
||||
git config --global user.email "user@example.com"
|
||||
git config --global user.name "User"
|
||||
./y.rs prepare
|
||||
|
||||
- name: Patch Cranelift
|
||||
run: |
|
||||
sed -i 's/cranelift-codegen = { version = "\w*.\w*.\w*", features = \["unwind", "all-arch"\] }/cranelift-codegen = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", features = ["unwind", "all-arch"] }/' Cargo.toml
|
||||
sed -i 's/cranelift-frontend = "\w*.\w*.\w*"/cranelift-frontend = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
|
||||
sed -i 's/cranelift-module = "\w*.\w*.\w*"/cranelift-module = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
|
||||
sed -i 's/cranelift-native = "\w*.\w*.\w*"/cranelift-native = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
|
||||
sed -i 's/cranelift-jit = { version = "\w*.\w*.\w*", optional = true }/cranelift-jit = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", optional = true }/' Cargo.toml
|
||||
sed -i 's/cranelift-object = "\w*.\w*.\w*"/cranelift-object = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
|
||||
|
||||
sed -i 's/object = { version = "0.27.0"/object = { version = "0.28.0"/' Cargo.toml
|
||||
|
||||
cat Cargo.toml
|
||||
|
||||
- name: Build without unstable features
|
||||
# This is the config rust-lang/rust uses for builds
|
||||
run: ./y.rs build --no-unstable-features
|
||||
|
||||
- name: Build
|
||||
run: ./y.rs build --sysroot none
|
||||
- name: Test
|
||||
run: |
|
||||
# Enable backtraces for easier debugging
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
# Reduce amount of benchmark runs as they are slow
|
||||
export COMPILE_RUNS=2
|
||||
export RUN_RUNS=2
|
||||
|
||||
# Enable extra checks
|
||||
export CG_CLIF_ENABLE_VERIFIER=1
|
||||
|
||||
./test.sh
|
||||
|
|
@ -10,73 +10,45 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-cargo-installed-crates
|
||||
|
||||
- name: Cache cargo registry and index
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Prepare dependencies
|
||||
- name: Use sparse cargo registry
|
||||
run: |
|
||||
git config --global user.email "user@example.com"
|
||||
git config --global user.name "User"
|
||||
./y.rs prepare
|
||||
cat >> ~/.cargo/config.toml <<EOF
|
||||
[unstable]
|
||||
sparse-registry = true
|
||||
EOF
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.rs prepare
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
# Enable backtraces for easier debugging
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
./scripts/test_bootstrap.sh
|
||||
run: ./scripts/test_bootstrap.sh
|
||||
rustc_test_suite:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Cache cargo installed crates
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-cargo-installed-crates
|
||||
|
||||
- name: Cache cargo registry and index
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
- name: Prepare dependencies
|
||||
- name: Use sparse cargo registry
|
||||
run: |
|
||||
git config --global user.email "user@example.com"
|
||||
git config --global user.name "User"
|
||||
./y.rs prepare
|
||||
cat >> ~/.cargo/config.toml <<EOF
|
||||
[unstable]
|
||||
sparse-registry = true
|
||||
EOF
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.rs prepare
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
# Enable backtraces for easier debugging
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
./scripts/test_rustc_tests.sh
|
||||
run: ./scripts/test_rustc_tests.sh
|
||||
|
|
|
|||
5
compiler/rustc_codegen_cranelift/.gitignore
vendored
5
compiler/rustc_codegen_cranelift/.gitignore
vendored
|
|
@ -1,4 +1,4 @@
|
|||
target
|
||||
/target
|
||||
**/*.rs.bk
|
||||
*.rlib
|
||||
*.o
|
||||
|
|
@ -11,9 +11,6 @@ perf.data.old
|
|||
/y.exe
|
||||
/y.pdb
|
||||
/build
|
||||
/build_sysroot/sysroot_src
|
||||
/build_sysroot/compiler-builtins
|
||||
/build_sysroot/rustc_version
|
||||
/dist
|
||||
/rust
|
||||
/download
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
|
||||
// source for rustc_* is not included in the rust-src component; disable the errors about this
|
||||
"rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
|
||||
"rust-analyzer.imports.granularity.enforce": true,
|
||||
|
|
@ -30,7 +32,7 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"sysroot_src": "./build_sysroot/sysroot_src/library",
|
||||
"sysroot_src": "./download/sysroot/sysroot_src/library",
|
||||
"crates": [
|
||||
{
|
||||
"root_module": "./example/std_example.rs",
|
||||
|
|
|
|||
|
|
@ -57,28 +57,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b62c772976416112fa4484cbd688cb6fb35fd430005c1c586224fc014018abad"
|
||||
checksum = "2f3d54eab028f5805ae3b26fd60eca3f3a9cfb76b989d9bab173be3f61356cc3"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b40ed2dd13c2ac7e24f88a3090c68ad3414eb1d066a95f8f1f7b3b819cb4e46"
|
||||
checksum = "2be1d5f2c3cca1efb691844bc1988b89c77291f13f778499a3f3c0cf49c0ed61"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bumpalo",
|
||||
"cranelift-bforest",
|
||||
"cranelift-codegen-meta",
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-egraph",
|
||||
"cranelift-entity",
|
||||
"cranelift-isle",
|
||||
"gimli",
|
||||
"hashbrown",
|
||||
"log",
|
||||
"regalloc2",
|
||||
"smallvec",
|
||||
|
|
@ -87,44 +87,30 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb927a8f1c27c34ee3759b6b0ffa528d2330405d5cc4511f0cab33fe2279f4b5"
|
||||
checksum = "3f9b1b1089750ce4005893af7ee00bb08a2cf1c9779999c0f7164cbc8ad2e0d2"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43dfa417b884a9ab488d95fd6b93b25e959321fe7bfd7a0a960ba5d7fb7ab927"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-egraph"
|
||||
version = "0.90.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a66b39785efd8513d2cca967ede56d6cc57c8d7986a595c7c47d0c78de8dce"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
"fxhash",
|
||||
"hashbrown",
|
||||
"indexmap",
|
||||
"log",
|
||||
"smallvec",
|
||||
]
|
||||
checksum = "cc5fbaec51de47297fd7304986fd53c8c0030abbe69728a60d72e1c63559318d"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0637ffde963cb5d759bc4d454cfa364b6509e6c74cdaa21298add0ed9276f346"
|
||||
checksum = "dab984c94593f876090fae92e984bdcc74d9b1acf740ab5f79036001c65cba13"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb72b8342685e850cb037350418f62cc4fc55d6c2eb9c7ca01b82f9f1a6f3d56"
|
||||
checksum = "6e0cb3102d21a2fe5f3210af608748ddd0cd09825ac12d42dc56ed5ed8725fe0"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
|
|
@ -134,15 +120,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-isle"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "850579cb9e4b448f7c301f1e6e6cbad99abe3f1f1d878a4994cb66e33c6db8cd"
|
||||
checksum = "72101dd1f441d629735143c41e00b3428f9267738176983ef588ff43382af0a0"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9add822ad66dcbe152b5ab57de10240a2df4505099f2f6c27159acb711890bd4"
|
||||
checksum = "6557f8ce44d498777f2495aa58d9692a4a37d6f84aa445750d666cef770b6a5c"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -159,9 +145,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "406b772626fc2664864cf947f3895a23b619895c7fff635f3622e2d857f4492f"
|
||||
checksum = "88807e1c0c47ec02fe433333ccbe56b480425418b1470e333205e11650697d72"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -169,9 +155,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d0a279e5bcba3e0466c734d8d8eb6bfc1ad29e95c37f3e4955b492b5616335e"
|
||||
checksum = "c22b0d9fcbe3fc5a1af9e7021b44ce42b930bcefac446ce22e02e8f9a0d67120"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
|
|
@ -180,9 +166,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-object"
|
||||
version = "0.90.1"
|
||||
version = "0.92.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39793c550f0c1d7db96c2fc1324583670c8143befe6edbfbaf1c68aba53be983"
|
||||
checksum = "341375758d7c3fedc0b5315f552e6f0feac46baf87c450a15e9455ef47c2b261"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -317,9 +303,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
|||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.4.2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5"
|
||||
checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c"
|
||||
dependencies = [
|
||||
"fxhash",
|
||||
"log",
|
||||
|
|
@ -347,7 +333,6 @@ dependencies = [
|
|||
"cranelift-frontend",
|
||||
"cranelift-jit",
|
||||
"cranelift-module",
|
||||
"cranelift-native",
|
||||
"cranelift-object",
|
||||
"gimli",
|
||||
"indexmap",
|
||||
|
|
@ -396,9 +381,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasmtime-jit-icache-coherence"
|
||||
version = "2.0.1"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6bbabb309c06cc238ee91b1455b748c45f0bdcab0dda2c2db85b0a1e69fcb66"
|
||||
checksum = "08fcba5ebd96da2a9f0747ab6337fe9788adfb3f63fa2c180520d665562d257e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -429,43 +414,57 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.36.1"
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
|
|
|
|||
|
|
@ -15,12 +15,14 @@ crate-type = ["dylib"]
|
|||
|
||||
[dependencies]
|
||||
# These have to be in sync with each other
|
||||
cranelift-codegen = { version = "0.90.1", features = ["unwind", "all-arch"] }
|
||||
cranelift-frontend = "0.90.1"
|
||||
cranelift-module = "0.90.1"
|
||||
cranelift-native = "0.90.1"
|
||||
cranelift-jit = { version = "0.90.1", optional = true }
|
||||
cranelift-object = "0.90.1"
|
||||
cranelift-codegen = { version = "0.92", features = ["unwind", "all-arch"] }
|
||||
cranelift-frontend = { version = "0.92" }
|
||||
cranelift-module = { version = "0.92" }
|
||||
# NOTE vendored as src/cranelift_native.rs
|
||||
# FIXME revert back to the external crate with Cranelift 0.93
|
||||
#cranelift-native = { version = "0.92" }
|
||||
cranelift-jit = { version = "0.92", optional = true }
|
||||
cranelift-object = { version = "0.92" }
|
||||
target-lexicon = "0.12.0"
|
||||
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
|
||||
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ If not please open an issue.
|
|||
## Building and testing
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git
|
||||
$ git clone https://github.com/bjorn3/rustc_codegen_cranelift
|
||||
$ cd rustc_codegen_cranelift
|
||||
$ ./y.rs prepare # download and patch sysroot src and install hyperfine for benchmarking
|
||||
$ ./y.rs prepare
|
||||
$ ./y.rs build
|
||||
```
|
||||
|
||||
|
|
@ -20,13 +20,12 @@ To run the test suite replace the last command with:
|
|||
$ ./test.sh
|
||||
```
|
||||
|
||||
This will implicitly build cg_clif too. Both `y.rs build` and `test.sh` accept a `--debug` argument to
|
||||
build in debug mode.
|
||||
For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.rs`.
|
||||
|
||||
Alternatively you can download a pre built version from [GHA]. It is listed in the artifacts section
|
||||
Alternatively you can download a pre built version from [Github Actions]. It is listed in the artifacts section
|
||||
of workflow runs. Unfortunately due to GHA restrictions you need to be logged in to access it.
|
||||
|
||||
[GHA]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
|
||||
[Github Actions]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
@ -53,7 +52,8 @@ configuration options.
|
|||
|
||||
* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041))
|
||||
* On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`.
|
||||
* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work)
|
||||
* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported)
|
||||
* Unwinding on panics ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1677), `-Cpanic=abort` is enabled by default)
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.77"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
|
@ -50,9 +50,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.85"
|
||||
version = "0.1.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
|
||||
checksum = "5dae98c88e576098d7ab13ebcb40cc43e5114b2beafe61a87cda9200649ff205"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -129,9 +129,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.138"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::path::Path;
|
||||
|
||||
use super::build_sysroot;
|
||||
use super::config;
|
||||
use super::path::Dirs;
|
||||
use super::prepare::GitRepo;
|
||||
use super::utils::{spawn_and_wait, CargoProject, Compiler};
|
||||
|
|
@ -10,41 +9,31 @@ use super::SysrootKind;
|
|||
pub(crate) static ABI_CAFE_REPO: GitRepo =
|
||||
GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
|
||||
|
||||
static ABI_CAFE: CargoProject = CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
|
||||
pub(crate) static ABI_CAFE: CargoProject =
|
||||
CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
|
||||
|
||||
pub(crate) fn run(
|
||||
channel: &str,
|
||||
sysroot_kind: SysrootKind,
|
||||
dirs: &Dirs,
|
||||
cg_clif_dylib: &Path,
|
||||
host_triple: &str,
|
||||
target_triple: &str,
|
||||
bootstrap_host_compiler: &Compiler,
|
||||
) {
|
||||
if !config::get_bool("testsuite.abi-cafe") {
|
||||
eprintln!("[SKIP] abi-cafe");
|
||||
return;
|
||||
}
|
||||
|
||||
if host_triple != target_triple {
|
||||
eprintln!("[SKIP] abi-cafe (cross-compilation not supported)");
|
||||
return;
|
||||
}
|
||||
|
||||
eprintln!("Building sysroot for abi-cafe");
|
||||
build_sysroot::build_sysroot(
|
||||
dirs,
|
||||
channel,
|
||||
sysroot_kind,
|
||||
cg_clif_dylib,
|
||||
host_triple,
|
||||
target_triple,
|
||||
bootstrap_host_compiler,
|
||||
bootstrap_host_compiler.triple.clone(),
|
||||
);
|
||||
|
||||
eprintln!("Running abi-cafe");
|
||||
|
||||
let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
|
||||
|
||||
let mut cmd = ABI_CAFE.run(&Compiler::host(), dirs);
|
||||
let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
|
||||
cmd.arg("--");
|
||||
cmd.arg("--pairs");
|
||||
cmd.args(pairs);
|
||||
|
|
|
|||
97
compiler/rustc_codegen_cranelift/build_system/bench.rs
Normal file
97
compiler/rustc_codegen_cranelift/build_system/bench.rs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::prepare::GitRepo;
|
||||
use super::rustc_info::get_file_name;
|
||||
use super::utils::{hyperfine_command, is_ci, spawn_and_wait, CargoProject, Compiler};
|
||||
|
||||
pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
|
||||
"ebobby",
|
||||
"simple-raytracer",
|
||||
"804a7a21b9e673a482797aa289a18ed480e4d813",
|
||||
"<none>",
|
||||
);
|
||||
|
||||
// Use a separate target dir for the initial LLVM build to reduce unnecessary recompiles
|
||||
pub(crate) static SIMPLE_RAYTRACER_LLVM: CargoProject =
|
||||
CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer_llvm");
|
||||
|
||||
pub(crate) static SIMPLE_RAYTRACER: CargoProject =
|
||||
CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
|
||||
|
||||
pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
||||
benchmark_simple_raytracer(dirs, bootstrap_host_compiler);
|
||||
}
|
||||
|
||||
fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
||||
if std::process::Command::new("hyperfine").output().is_err() {
|
||||
eprintln!("Hyperfine not installed");
|
||||
eprintln!("Hint: Try `cargo install hyperfine` to install hyperfine");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
eprintln!("[LLVM BUILD] simple-raytracer");
|
||||
let build_cmd = SIMPLE_RAYTRACER_LLVM.build(bootstrap_host_compiler, dirs);
|
||||
spawn_and_wait(build_cmd);
|
||||
fs::copy(
|
||||
SIMPLE_RAYTRACER_LLVM
|
||||
.target_dir(dirs)
|
||||
.join(&bootstrap_host_compiler.triple)
|
||||
.join("debug")
|
||||
.join(get_file_name("main", "bin")),
|
||||
RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let run_runs = env::var("RUN_RUNS")
|
||||
.unwrap_or(if is_ci() { "2" } else { "10" }.to_string())
|
||||
.parse()
|
||||
.unwrap();
|
||||
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
|
||||
let cargo_clif =
|
||||
RelPath::DIST.to_path(dirs).join(get_file_name("cargo_clif", "bin").replace('_', "-"));
|
||||
let manifest_path = SIMPLE_RAYTRACER.manifest_path(dirs);
|
||||
let target_dir = SIMPLE_RAYTRACER.target_dir(dirs);
|
||||
|
||||
let clean_cmd = format!(
|
||||
"cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
let llvm_build_cmd = format!(
|
||||
"cargo build --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
let clif_build_cmd = format!(
|
||||
"{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
cargo_clif = cargo_clif.display(),
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
|
||||
let bench_compile =
|
||||
hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd);
|
||||
|
||||
spawn_and_wait(bench_compile);
|
||||
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
|
||||
fs::copy(
|
||||
target_dir.join("debug").join(get_file_name("main", "bin")),
|
||||
RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_clif", "bin")),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut bench_run = hyperfine_command(
|
||||
0,
|
||||
run_runs,
|
||||
None,
|
||||
Path::new(".").join(get_file_name("raytracer_cg_llvm", "bin")).to_str().unwrap(),
|
||||
Path::new(".").join(get_file_name("raytracer_cg_clif", "bin")).to_str().unwrap(),
|
||||
);
|
||||
bench_run.current_dir(RelPath::BUILD.to_path(dirs));
|
||||
spawn_and_wait(bench_run);
|
||||
}
|
||||
|
|
@ -5,15 +5,15 @@ use super::path::{Dirs, RelPath};
|
|||
use super::rustc_info::get_file_name;
|
||||
use super::utils::{is_ci, CargoProject, Compiler};
|
||||
|
||||
static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
|
||||
pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
|
||||
|
||||
pub(crate) fn build_backend(
|
||||
dirs: &Dirs,
|
||||
channel: &str,
|
||||
host_triple: &str,
|
||||
bootstrap_host_compiler: &Compiler,
|
||||
use_unstable_features: bool,
|
||||
) -> PathBuf {
|
||||
let mut cmd = CG_CLIF.build(&Compiler::host(), dirs);
|
||||
let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs);
|
||||
|
||||
cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
|
||||
|
||||
|
|
@ -25,6 +25,8 @@ pub(crate) fn build_backend(
|
|||
|
||||
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
|
||||
cmd.env("CARGO_BUILD_INCREMENTAL", "false");
|
||||
|
||||
cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true");
|
||||
}
|
||||
|
||||
if use_unstable_features {
|
||||
|
|
@ -46,7 +48,7 @@ pub(crate) fn build_backend(
|
|||
|
||||
CG_CLIF
|
||||
.target_dir(dirs)
|
||||
.join(host_triple)
|
||||
.join(&bootstrap_host_compiler.triple)
|
||||
.join(channel)
|
||||
.join(get_file_name("rustc_codegen_cranelift", "dylib"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,32 @@
|
|||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command};
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::{get_file_name, get_rustc_version, get_wrapper_file_name};
|
||||
use super::utils::{spawn_and_wait, try_hard_link, CargoProject, Compiler};
|
||||
use super::rustc_info::{get_file_name, get_rustc_version, get_toolchain_name};
|
||||
use super::utils::{remove_dir_if_exists, spawn_and_wait, try_hard_link, CargoProject, Compiler};
|
||||
use super::SysrootKind;
|
||||
|
||||
static DIST_DIR: RelPath = RelPath::DIST;
|
||||
static BIN_DIR: RelPath = RelPath::DIST.join("bin");
|
||||
static LIB_DIR: RelPath = RelPath::DIST.join("lib");
|
||||
static RUSTLIB_DIR: RelPath = LIB_DIR.join("rustlib");
|
||||
|
||||
pub(crate) fn build_sysroot(
|
||||
dirs: &Dirs,
|
||||
channel: &str,
|
||||
sysroot_kind: SysrootKind,
|
||||
cg_clif_dylib_src: &Path,
|
||||
host_triple: &str,
|
||||
target_triple: &str,
|
||||
) {
|
||||
bootstrap_host_compiler: &Compiler,
|
||||
target_triple: String,
|
||||
) -> Compiler {
|
||||
eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
|
||||
|
||||
DIST_DIR.ensure_fresh(dirs);
|
||||
BIN_DIR.ensure_exists(dirs);
|
||||
LIB_DIR.ensure_exists(dirs);
|
||||
|
||||
let is_native = bootstrap_host_compiler.triple == target_triple;
|
||||
|
||||
// Copy the backend
|
||||
let cg_clif_dylib_path = if cfg!(windows) {
|
||||
// Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
|
||||
|
|
@ -35,129 +36,169 @@ pub(crate) fn build_sysroot(
|
|||
LIB_DIR
|
||||
}
|
||||
.to_path(dirs)
|
||||
.join(get_file_name("rustc_codegen_cranelift", "dylib"));
|
||||
.join(cg_clif_dylib_src.file_name().unwrap());
|
||||
try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
|
||||
|
||||
// Build and copy rustc and cargo wrappers
|
||||
let wrapper_base_name = get_file_name("____", "bin");
|
||||
let toolchain_name = get_toolchain_name();
|
||||
for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] {
|
||||
let wrapper_name = get_wrapper_file_name(wrapper, "bin");
|
||||
let wrapper_name = wrapper_base_name.replace("____", wrapper);
|
||||
|
||||
let mut build_cargo_wrapper_cmd = Command::new("rustc");
|
||||
let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc);
|
||||
build_cargo_wrapper_cmd
|
||||
.env("TOOLCHAIN_NAME", toolchain_name.clone())
|
||||
.arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
|
||||
.arg("-o")
|
||||
.arg(DIST_DIR.to_path(dirs).join(wrapper_name))
|
||||
.arg("-g");
|
||||
.arg("-Cstrip=debuginfo");
|
||||
spawn_and_wait(build_cargo_wrapper_cmd);
|
||||
}
|
||||
|
||||
let default_sysroot = super::rustc_info::get_default_sysroot();
|
||||
let host = build_sysroot_for_triple(
|
||||
dirs,
|
||||
channel,
|
||||
bootstrap_host_compiler.clone(),
|
||||
&cg_clif_dylib_path,
|
||||
sysroot_kind,
|
||||
);
|
||||
host.install_into_sysroot(&DIST_DIR.to_path(dirs));
|
||||
|
||||
let host_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(host_triple).join("lib");
|
||||
let target_rustlib_lib = RUSTLIB_DIR.to_path(dirs).join(target_triple).join("lib");
|
||||
fs::create_dir_all(&host_rustlib_lib).unwrap();
|
||||
fs::create_dir_all(&target_rustlib_lib).unwrap();
|
||||
|
||||
if target_triple == "x86_64-pc-windows-gnu" {
|
||||
if !default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib").exists() {
|
||||
eprintln!(
|
||||
"The x86_64-pc-windows-gnu target needs to be installed first before it is possible \
|
||||
to compile a sysroot for it.",
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
for file in fs::read_dir(
|
||||
default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
|
||||
if !is_native {
|
||||
build_sysroot_for_triple(
|
||||
dirs,
|
||||
channel,
|
||||
{
|
||||
let mut bootstrap_target_compiler = bootstrap_host_compiler.clone();
|
||||
bootstrap_target_compiler.triple = target_triple.clone();
|
||||
bootstrap_target_compiler.set_cross_linker_and_runner();
|
||||
bootstrap_target_compiler
|
||||
},
|
||||
&cg_clif_dylib_path,
|
||||
sysroot_kind,
|
||||
)
|
||||
.unwrap()
|
||||
{
|
||||
let file = file.unwrap().path();
|
||||
if file.extension().map_or(true, |ext| ext.to_str().unwrap() != "o") {
|
||||
continue; // only copy object files
|
||||
}
|
||||
try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
|
||||
.install_into_sysroot(&DIST_DIR.to_path(dirs));
|
||||
}
|
||||
|
||||
// Copy std for the host to the lib dir. This is necessary for the jit mode to find
|
||||
// libstd.
|
||||
for lib in host.libs {
|
||||
let filename = lib.file_name().unwrap().to_str().unwrap();
|
||||
if filename.contains("std-") && !filename.contains(".rlib") {
|
||||
try_hard_link(&lib, LIB_DIR.to_path(dirs).join(lib.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
match sysroot_kind {
|
||||
SysrootKind::None => {} // Nothing to do
|
||||
SysrootKind::Llvm => {
|
||||
for file in fs::read_dir(
|
||||
default_sysroot.join("lib").join("rustlib").join(host_triple).join("lib"),
|
||||
)
|
||||
.unwrap()
|
||||
{
|
||||
let file = file.unwrap().path();
|
||||
let file_name_str = file.file_name().unwrap().to_str().unwrap();
|
||||
if (file_name_str.contains("rustc_")
|
||||
&& !file_name_str.contains("rustc_std_workspace_")
|
||||
&& !file_name_str.contains("rustc_demangle"))
|
||||
|| file_name_str.contains("chalk")
|
||||
|| file_name_str.contains("tracing")
|
||||
|| file_name_str.contains("regex")
|
||||
{
|
||||
// These are large crates that are part of the rustc-dev component and are not
|
||||
// necessary to run regular programs.
|
||||
continue;
|
||||
}
|
||||
try_hard_link(&file, host_rustlib_lib.join(file.file_name().unwrap()));
|
||||
}
|
||||
let mut target_compiler = {
|
||||
let dirs: &Dirs = &dirs;
|
||||
let rustc_clif =
|
||||
RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustc-clif"));
|
||||
let rustdoc_clif =
|
||||
RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustdoc-clif"));
|
||||
|
||||
if target_triple != host_triple {
|
||||
for file in fs::read_dir(
|
||||
default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
|
||||
)
|
||||
.unwrap()
|
||||
{
|
||||
let file = file.unwrap().path();
|
||||
try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
Compiler {
|
||||
cargo: bootstrap_host_compiler.cargo.clone(),
|
||||
rustc: rustc_clif.clone(),
|
||||
rustdoc: rustdoc_clif.clone(),
|
||||
rustflags: String::new(),
|
||||
rustdocflags: String::new(),
|
||||
triple: target_triple,
|
||||
runner: vec![],
|
||||
}
|
||||
SysrootKind::Clif => {
|
||||
build_clif_sysroot_for_triple(dirs, channel, host_triple, &cg_clif_dylib_path, None);
|
||||
};
|
||||
if !is_native {
|
||||
target_compiler.set_cross_linker_and_runner();
|
||||
}
|
||||
target_compiler
|
||||
}
|
||||
|
||||
if host_triple != target_triple {
|
||||
// When cross-compiling it is often necessary to manually pick the right linker
|
||||
let linker = match target_triple {
|
||||
"aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu-gcc"),
|
||||
"s390x-unknown-linux-gnu" => Some("s390x-linux-gnu-gcc"),
|
||||
_ => None,
|
||||
};
|
||||
build_clif_sysroot_for_triple(
|
||||
dirs,
|
||||
channel,
|
||||
target_triple,
|
||||
&cg_clif_dylib_path,
|
||||
linker,
|
||||
);
|
||||
}
|
||||
struct SysrootTarget {
|
||||
triple: String,
|
||||
libs: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
// Copy std for the host to the lib dir. This is necessary for the jit mode to find
|
||||
// libstd.
|
||||
for file in fs::read_dir(host_rustlib_lib).unwrap() {
|
||||
let file = file.unwrap().path();
|
||||
let filename = file.file_name().unwrap().to_str().unwrap();
|
||||
if filename.contains("std-") && !filename.contains(".rlib") {
|
||||
try_hard_link(&file, LIB_DIR.to_path(dirs).join(file.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
impl SysrootTarget {
|
||||
fn install_into_sysroot(&self, sysroot: &Path) {
|
||||
if self.libs.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let target_rustlib_lib = sysroot.join("lib").join("rustlib").join(&self.triple).join("lib");
|
||||
fs::create_dir_all(&target_rustlib_lib).unwrap();
|
||||
|
||||
for lib in &self.libs {
|
||||
try_hard_link(lib, target_rustlib_lib.join(lib.file_name().unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME move to download/ or dist/
|
||||
pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = RelPath::BUILD_SYSROOT.join("rustc_version");
|
||||
pub(crate) static SYSROOT_SRC: RelPath = RelPath::BUILD_SYSROOT.join("sysroot_src");
|
||||
static STANDARD_LIBRARY: CargoProject = CargoProject::new(&RelPath::BUILD_SYSROOT, "build_sysroot");
|
||||
pub(crate) static ORIG_BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
|
||||
pub(crate) static BUILD_SYSROOT: RelPath = RelPath::DOWNLOAD.join("sysroot");
|
||||
pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = BUILD_SYSROOT.join("rustc_version");
|
||||
pub(crate) static SYSROOT_SRC: RelPath = BUILD_SYSROOT.join("sysroot_src");
|
||||
pub(crate) static STANDARD_LIBRARY: CargoProject =
|
||||
CargoProject::new(&BUILD_SYSROOT, "build_sysroot");
|
||||
pub(crate) static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup");
|
||||
|
||||
#[must_use]
|
||||
fn build_sysroot_for_triple(
|
||||
dirs: &Dirs,
|
||||
channel: &str,
|
||||
compiler: Compiler,
|
||||
cg_clif_dylib_path: &Path,
|
||||
sysroot_kind: SysrootKind,
|
||||
) -> SysrootTarget {
|
||||
match sysroot_kind {
|
||||
SysrootKind::None => build_rtstartup(dirs, &compiler)
|
||||
.unwrap_or(SysrootTarget { triple: compiler.triple, libs: vec![] }),
|
||||
SysrootKind::Llvm => build_llvm_sysroot_for_triple(compiler),
|
||||
SysrootKind::Clif => {
|
||||
build_clif_sysroot_for_triple(dirs, channel, compiler, &cg_clif_dylib_path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget {
|
||||
let default_sysroot = super::rustc_info::get_default_sysroot(&compiler.rustc);
|
||||
|
||||
let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] };
|
||||
|
||||
for entry in fs::read_dir(
|
||||
default_sysroot.join("lib").join("rustlib").join(&target_libs.triple).join("lib"),
|
||||
)
|
||||
.unwrap()
|
||||
{
|
||||
let entry = entry.unwrap();
|
||||
if entry.file_type().unwrap().is_dir() {
|
||||
continue;
|
||||
}
|
||||
let file = entry.path();
|
||||
let file_name_str = file.file_name().unwrap().to_str().unwrap();
|
||||
if (file_name_str.contains("rustc_")
|
||||
&& !file_name_str.contains("rustc_std_workspace_")
|
||||
&& !file_name_str.contains("rustc_demangle"))
|
||||
|| file_name_str.contains("chalk")
|
||||
|| file_name_str.contains("tracing")
|
||||
|| file_name_str.contains("regex")
|
||||
{
|
||||
// These are large crates that are part of the rustc-dev component and are not
|
||||
// necessary to run regular programs.
|
||||
continue;
|
||||
}
|
||||
target_libs.libs.push(file);
|
||||
}
|
||||
|
||||
target_libs
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn build_clif_sysroot_for_triple(
|
||||
dirs: &Dirs,
|
||||
channel: &str,
|
||||
triple: &str,
|
||||
mut compiler: Compiler,
|
||||
cg_clif_dylib_path: &Path,
|
||||
linker: Option<&str>,
|
||||
) {
|
||||
) -> SysrootTarget {
|
||||
match fs::read_to_string(SYSROOT_RUSTC_VERSION.to_path(dirs)) {
|
||||
Err(e) => {
|
||||
eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
|
||||
|
|
@ -165,7 +206,7 @@ fn build_clif_sysroot_for_triple(
|
|||
process::exit(1);
|
||||
}
|
||||
Ok(source_version) => {
|
||||
let rustc_version = get_rustc_version();
|
||||
let rustc_version = get_rustc_version(&compiler.rustc);
|
||||
if source_version != rustc_version {
|
||||
eprintln!("The patched sysroot source is outdated");
|
||||
eprintln!("Source version: {}", source_version.trim());
|
||||
|
|
@ -176,29 +217,32 @@ fn build_clif_sysroot_for_triple(
|
|||
}
|
||||
}
|
||||
|
||||
let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(triple).join(channel);
|
||||
let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
|
||||
|
||||
if let Some(rtstartup_target_libs) = build_rtstartup(dirs, &compiler) {
|
||||
rtstartup_target_libs.install_into_sysroot(&RTSTARTUP_SYSROOT.to_path(dirs));
|
||||
|
||||
target_libs.libs.extend(rtstartup_target_libs.libs);
|
||||
}
|
||||
|
||||
let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join(channel);
|
||||
|
||||
if !super::config::get_bool("keep_sysroot") {
|
||||
// Cleanup the deps dir, but keep build scripts and the incremental cache for faster
|
||||
// recompilation as they are not affected by changes in cg_clif.
|
||||
if build_dir.join("deps").exists() {
|
||||
fs::remove_dir_all(build_dir.join("deps")).unwrap();
|
||||
}
|
||||
remove_dir_if_exists(&build_dir.join("deps"));
|
||||
}
|
||||
|
||||
// Build sysroot
|
||||
let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
|
||||
let mut rustflags = " -Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
|
||||
rustflags.push_str(&format!(" -Zcodegen-backend={}", cg_clif_dylib_path.to_str().unwrap()));
|
||||
rustflags.push_str(&format!(" --sysroot={}", DIST_DIR.to_path(dirs).to_str().unwrap()));
|
||||
// Necessary for MinGW to find rsbegin.o and rsend.o
|
||||
rustflags
|
||||
.push_str(&format!(" --sysroot={}", RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap()));
|
||||
if channel == "release" {
|
||||
rustflags.push_str(" -Zmir-opt-level=3");
|
||||
}
|
||||
if let Some(linker) = linker {
|
||||
use std::fmt::Write;
|
||||
write!(rustflags, " -Clinker={}", linker).unwrap();
|
||||
}
|
||||
let mut compiler = Compiler::with_triple(triple.to_owned());
|
||||
compiler.rustflags = rustflags;
|
||||
compiler.rustflags += &rustflags;
|
||||
let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
|
||||
if channel == "release" {
|
||||
build_cmd.arg("--release");
|
||||
|
|
@ -206,7 +250,6 @@ fn build_clif_sysroot_for_triple(
|
|||
build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
|
||||
spawn_and_wait(build_cmd);
|
||||
|
||||
// Copy all relevant files to the sysroot
|
||||
for entry in fs::read_dir(build_dir.join("deps")).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
if let Some(ext) = entry.path().extension() {
|
||||
|
|
@ -216,9 +259,35 @@ fn build_clif_sysroot_for_triple(
|
|||
} else {
|
||||
continue;
|
||||
};
|
||||
try_hard_link(
|
||||
entry.path(),
|
||||
RUSTLIB_DIR.to_path(dirs).join(triple).join("lib").join(entry.file_name()),
|
||||
);
|
||||
target_libs.libs.push(entry.path());
|
||||
}
|
||||
|
||||
target_libs
|
||||
}
|
||||
|
||||
fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
|
||||
if !compiler.triple.ends_with("windows-gnu") {
|
||||
return None;
|
||||
}
|
||||
|
||||
RTSTARTUP_SYSROOT.ensure_fresh(dirs);
|
||||
|
||||
let rtstartup_src = SYSROOT_SRC.to_path(dirs).join("library").join("rtstartup");
|
||||
let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
|
||||
|
||||
for file in ["rsbegin", "rsend"] {
|
||||
let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o"));
|
||||
let mut build_rtstartup_cmd = Command::new(&compiler.rustc);
|
||||
build_rtstartup_cmd
|
||||
.arg("--target")
|
||||
.arg(&compiler.triple)
|
||||
.arg("--emit=obj")
|
||||
.arg("-o")
|
||||
.arg(&obj)
|
||||
.arg(rtstartup_src.join(format!("{file}.rs")));
|
||||
spawn_and_wait(build_rtstartup_cmd);
|
||||
target_libs.libs.push(obj.clone());
|
||||
}
|
||||
|
||||
Some(target_libs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use std::env;
|
|||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
||||
use self::utils::is_ci;
|
||||
use self::utils::{is_ci, Compiler};
|
||||
|
||||
mod abi_cafe;
|
||||
mod bench;
|
||||
mod build_backend;
|
||||
mod build_sysroot;
|
||||
mod config;
|
||||
|
|
@ -14,31 +15,8 @@ mod rustc_info;
|
|||
mod tests;
|
||||
mod utils;
|
||||
|
||||
const USAGE: &str = r#"The build system of cg_clif.
|
||||
|
||||
USAGE:
|
||||
./y.rs prepare [--out-dir DIR]
|
||||
./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
|
||||
./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
|
||||
|
||||
OPTIONS:
|
||||
--sysroot none|clif|llvm
|
||||
Which sysroot libraries to use:
|
||||
`none` will not include any standard library in the sysroot.
|
||||
`clif` will build the standard library using Cranelift.
|
||||
`llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM.
|
||||
|
||||
--out-dir DIR
|
||||
Specify the directory in which the download, build and dist directories are stored.
|
||||
By default this is the working directory.
|
||||
|
||||
--no-unstable-features
|
||||
fSome features are not yet ready for production usage. This option will disable these
|
||||
features. This includes the JIT mode and inline assembly support.
|
||||
"#;
|
||||
|
||||
fn usage() {
|
||||
eprintln!("{USAGE}");
|
||||
eprintln!("{}", include_str!("usage.txt"));
|
||||
}
|
||||
|
||||
macro_rules! arg_error {
|
||||
|
|
@ -54,6 +32,8 @@ enum Command {
|
|||
Prepare,
|
||||
Build,
|
||||
Test,
|
||||
AbiCafe,
|
||||
Bench,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -64,12 +44,17 @@ pub(crate) enum SysrootKind {
|
|||
}
|
||||
|
||||
pub fn main() {
|
||||
env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
|
||||
if env::var("RUST_BACKTRACE").is_err() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
}
|
||||
env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
|
||||
|
||||
if is_ci() {
|
||||
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
|
||||
env::set_var("CARGO_BUILD_INCREMENTAL", "false");
|
||||
|
||||
// Enable the Cranelift verifier
|
||||
env::set_var("CG_CLIF_ENABLE_VERIFIER", "1");
|
||||
}
|
||||
|
||||
let mut args = env::args().skip(1);
|
||||
|
|
@ -77,6 +62,8 @@ pub fn main() {
|
|||
Some("prepare") => Command::Prepare,
|
||||
Some("build") => Command::Build,
|
||||
Some("test") => Command::Test,
|
||||
Some("abi-cafe") => Command::AbiCafe,
|
||||
Some("bench") => Command::Bench,
|
||||
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
|
||||
Some(command) => arg_error!("Unknown command {}", command),
|
||||
None => {
|
||||
|
|
@ -112,24 +99,16 @@ pub fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
|
||||
host_triple
|
||||
} else if let Some(host_triple) = config::get_value("host") {
|
||||
host_triple
|
||||
} else {
|
||||
rustc_info::get_host_triple()
|
||||
};
|
||||
let target_triple = if let Ok(target_triple) = std::env::var("TARGET_TRIPLE") {
|
||||
if target_triple != "" {
|
||||
target_triple
|
||||
} else {
|
||||
host_triple.clone() // Empty target triple can happen on GHA
|
||||
}
|
||||
} else if let Some(target_triple) = config::get_value("target") {
|
||||
target_triple
|
||||
} else {
|
||||
host_triple.clone()
|
||||
};
|
||||
let bootstrap_host_compiler = Compiler::bootstrap_with_triple(
|
||||
std::env::var("HOST_TRIPLE")
|
||||
.ok()
|
||||
.or_else(|| config::get_value("host"))
|
||||
.unwrap_or_else(|| rustc_info::get_host_triple()),
|
||||
);
|
||||
let target_triple = std::env::var("TARGET_TRIPLE")
|
||||
.ok()
|
||||
.or_else(|| config::get_value("target"))
|
||||
.unwrap_or_else(|| bootstrap_host_compiler.triple.clone());
|
||||
|
||||
// FIXME allow changing the location of these dirs using cli arguments
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
|
|
@ -157,8 +136,15 @@ pub fn main() {
|
|||
process::exit(0);
|
||||
}
|
||||
|
||||
let cg_clif_dylib =
|
||||
build_backend::build_backend(&dirs, channel, &host_triple, use_unstable_features);
|
||||
env::set_var("RUSTC", "rustc_should_be_set_explicitly");
|
||||
env::set_var("RUSTDOC", "rustdoc_should_be_set_explicitly");
|
||||
|
||||
let cg_clif_dylib = build_backend::build_backend(
|
||||
&dirs,
|
||||
channel,
|
||||
&bootstrap_host_compiler,
|
||||
use_unstable_features,
|
||||
);
|
||||
match command {
|
||||
Command::Prepare => {
|
||||
// Handled above
|
||||
|
|
@ -169,28 +155,37 @@ pub fn main() {
|
|||
channel,
|
||||
sysroot_kind,
|
||||
&cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
);
|
||||
|
||||
abi_cafe::run(
|
||||
channel,
|
||||
sysroot_kind,
|
||||
&dirs,
|
||||
&cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
&bootstrap_host_compiler,
|
||||
target_triple.clone(),
|
||||
);
|
||||
}
|
||||
Command::AbiCafe => {
|
||||
if bootstrap_host_compiler.triple != target_triple {
|
||||
eprintln!("Abi-cafe doesn't support cross-compilation");
|
||||
process::exit(1);
|
||||
}
|
||||
abi_cafe::run(channel, sysroot_kind, &dirs, &cg_clif_dylib, &bootstrap_host_compiler);
|
||||
}
|
||||
Command::Build => {
|
||||
build_sysroot::build_sysroot(
|
||||
&dirs,
|
||||
channel,
|
||||
sysroot_kind,
|
||||
&cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
&bootstrap_host_compiler,
|
||||
target_triple,
|
||||
);
|
||||
}
|
||||
Command::Bench => {
|
||||
build_sysroot::build_sysroot(
|
||||
&dirs,
|
||||
channel,
|
||||
sysroot_kind,
|
||||
&cg_clif_dylib,
|
||||
&bootstrap_host_compiler,
|
||||
target_triple,
|
||||
);
|
||||
bench::benchmark(&dirs, &bootstrap_host_compiler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::utils::remove_dir_if_exists;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Dirs {
|
||||
pub(crate) source_dir: PathBuf,
|
||||
|
|
@ -42,7 +44,6 @@ impl RelPath {
|
|||
pub(crate) const DIST: RelPath = RelPath::Base(PathBase::Dist);
|
||||
|
||||
pub(crate) const SCRIPTS: RelPath = RelPath::SOURCE.join("scripts");
|
||||
pub(crate) const BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
|
||||
pub(crate) const PATCHES: RelPath = RelPath::SOURCE.join("patches");
|
||||
|
||||
pub(crate) const fn join(&'static self, suffix: &'static str) -> RelPath {
|
||||
|
|
@ -62,9 +63,7 @@ impl RelPath {
|
|||
|
||||
pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
|
||||
let path = self.to_path(dirs);
|
||||
if path.exists() {
|
||||
fs::remove_dir_all(&path).unwrap();
|
||||
}
|
||||
remove_dir_if_exists(&path);
|
||||
fs::create_dir_all(path).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,73 +3,55 @@ use std::fs;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use super::build_sysroot::{SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
|
||||
use super::build_sysroot::{BUILD_SYSROOT, ORIG_BUILD_SYSROOT, SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::{get_file_name, get_rustc_path, get_rustc_version};
|
||||
use super::utils::{copy_dir_recursively, spawn_and_wait, Compiler};
|
||||
use super::rustc_info::{get_default_sysroot, get_rustc_version};
|
||||
use super::utils::{copy_dir_recursively, git_command, retry_spawn_and_wait, spawn_and_wait};
|
||||
|
||||
pub(crate) fn prepare(dirs: &Dirs) {
|
||||
if RelPath::DOWNLOAD.to_path(dirs).exists() {
|
||||
std::fs::remove_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
|
||||
}
|
||||
std::fs::create_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
|
||||
RelPath::DOWNLOAD.ensure_fresh(dirs);
|
||||
|
||||
spawn_and_wait(super::build_backend::CG_CLIF.fetch("cargo", dirs));
|
||||
|
||||
prepare_sysroot(dirs);
|
||||
|
||||
// FIXME maybe install this only locally?
|
||||
eprintln!("[INSTALL] hyperfine");
|
||||
Command::new("cargo")
|
||||
.arg("install")
|
||||
.arg("hyperfine")
|
||||
.env_remove("CARGO_TARGET_DIR")
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait()
|
||||
.unwrap();
|
||||
spawn_and_wait(super::build_sysroot::STANDARD_LIBRARY.fetch("cargo", dirs));
|
||||
spawn_and_wait(super::tests::LIBCORE_TESTS.fetch("cargo", dirs));
|
||||
|
||||
super::abi_cafe::ABI_CAFE_REPO.fetch(dirs);
|
||||
spawn_and_wait(super::abi_cafe::ABI_CAFE.fetch("cargo", dirs));
|
||||
super::tests::RAND_REPO.fetch(dirs);
|
||||
spawn_and_wait(super::tests::RAND.fetch("cargo", dirs));
|
||||
super::tests::REGEX_REPO.fetch(dirs);
|
||||
spawn_and_wait(super::tests::REGEX.fetch("cargo", dirs));
|
||||
super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
|
||||
super::tests::SIMPLE_RAYTRACER_REPO.fetch(dirs);
|
||||
|
||||
eprintln!("[LLVM BUILD] simple-raytracer");
|
||||
let host_compiler = Compiler::host();
|
||||
let build_cmd = super::tests::SIMPLE_RAYTRACER.build(&host_compiler, dirs);
|
||||
spawn_and_wait(build_cmd);
|
||||
fs::copy(
|
||||
super::tests::SIMPLE_RAYTRACER
|
||||
.target_dir(dirs)
|
||||
.join(&host_compiler.triple)
|
||||
.join("debug")
|
||||
.join(get_file_name("main", "bin")),
|
||||
RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
|
||||
)
|
||||
.unwrap();
|
||||
spawn_and_wait(super::tests::PORTABLE_SIMD.fetch("cargo", dirs));
|
||||
super::bench::SIMPLE_RAYTRACER_REPO.fetch(dirs);
|
||||
spawn_and_wait(super::bench::SIMPLE_RAYTRACER.fetch("cargo", dirs));
|
||||
}
|
||||
|
||||
fn prepare_sysroot(dirs: &Dirs) {
|
||||
let rustc_path = get_rustc_path();
|
||||
let sysroot_src_orig = rustc_path.parent().unwrap().join("../lib/rustlib/src/rust");
|
||||
let sysroot_src = SYSROOT_SRC;
|
||||
|
||||
let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust");
|
||||
assert!(sysroot_src_orig.exists());
|
||||
|
||||
sysroot_src.ensure_fresh(dirs);
|
||||
fs::create_dir_all(sysroot_src.to_path(dirs).join("library")).unwrap();
|
||||
eprintln!("[COPY] sysroot src");
|
||||
|
||||
// FIXME ensure builds error out or update the copy if any of the files copied here change
|
||||
BUILD_SYSROOT.ensure_fresh(dirs);
|
||||
copy_dir_recursively(&ORIG_BUILD_SYSROOT.to_path(dirs), &BUILD_SYSROOT.to_path(dirs));
|
||||
|
||||
fs::create_dir_all(SYSROOT_SRC.to_path(dirs).join("library")).unwrap();
|
||||
copy_dir_recursively(
|
||||
&sysroot_src_orig.join("library"),
|
||||
&sysroot_src.to_path(dirs).join("library"),
|
||||
&SYSROOT_SRC.to_path(dirs).join("library"),
|
||||
);
|
||||
|
||||
let rustc_version = get_rustc_version();
|
||||
let rustc_version = get_rustc_version(Path::new("rustc"));
|
||||
fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
|
||||
|
||||
eprintln!("[GIT] init");
|
||||
init_git_repo(&sysroot_src.to_path(dirs));
|
||||
init_git_repo(&SYSROOT_SRC.to_path(dirs));
|
||||
|
||||
apply_patches(dirs, "sysroot", &sysroot_src.to_path(dirs));
|
||||
apply_patches(dirs, "sysroot", &SYSROOT_SRC.to_path(dirs));
|
||||
}
|
||||
|
||||
pub(crate) struct GitRepo {
|
||||
|
|
@ -118,14 +100,14 @@ impl GitRepo {
|
|||
fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
|
||||
eprintln!("[CLONE] {}", repo);
|
||||
// Ignore exit code as the repo may already have been checked out
|
||||
Command::new("git").arg("clone").arg(repo).arg(&download_dir).spawn().unwrap().wait().unwrap();
|
||||
git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap();
|
||||
|
||||
let mut clean_cmd = Command::new("git");
|
||||
clean_cmd.arg("checkout").arg("--").arg(".").current_dir(&download_dir);
|
||||
let mut clean_cmd = git_command(download_dir, "checkout");
|
||||
clean_cmd.arg("--").arg(".");
|
||||
spawn_and_wait(clean_cmd);
|
||||
|
||||
let mut checkout_cmd = Command::new("git");
|
||||
checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(download_dir);
|
||||
let mut checkout_cmd = git_command(download_dir, "checkout");
|
||||
checkout_cmd.arg("-q").arg(rev);
|
||||
spawn_and_wait(checkout_cmd);
|
||||
}
|
||||
|
||||
|
|
@ -149,8 +131,22 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo:
|
|||
|
||||
// Download zip archive
|
||||
let mut download_cmd = Command::new("curl");
|
||||
download_cmd.arg("--location").arg("--output").arg(&archive_file).arg(archive_url);
|
||||
spawn_and_wait(download_cmd);
|
||||
download_cmd
|
||||
.arg("--max-time")
|
||||
.arg("600")
|
||||
.arg("-y")
|
||||
.arg("30")
|
||||
.arg("-Y")
|
||||
.arg("10")
|
||||
.arg("--connect-timeout")
|
||||
.arg("30")
|
||||
.arg("--continue-at")
|
||||
.arg("-")
|
||||
.arg("--location")
|
||||
.arg("--output")
|
||||
.arg(&archive_file)
|
||||
.arg(archive_url);
|
||||
retry_spawn_and_wait(5, download_cmd);
|
||||
|
||||
// Unpack tar archive
|
||||
let mut unpack_cmd = Command::new("tar");
|
||||
|
|
@ -167,25 +163,16 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo:
|
|||
}
|
||||
|
||||
fn init_git_repo(repo_dir: &Path) {
|
||||
let mut git_init_cmd = Command::new("git");
|
||||
git_init_cmd.arg("init").arg("-q").current_dir(repo_dir);
|
||||
let mut git_init_cmd = git_command(repo_dir, "init");
|
||||
git_init_cmd.arg("-q");
|
||||
spawn_and_wait(git_init_cmd);
|
||||
|
||||
let mut git_add_cmd = Command::new("git");
|
||||
git_add_cmd.arg("add").arg(".").current_dir(repo_dir);
|
||||
let mut git_add_cmd = git_command(repo_dir, "add");
|
||||
git_add_cmd.arg(".");
|
||||
spawn_and_wait(git_add_cmd);
|
||||
|
||||
let mut git_commit_cmd = Command::new("git");
|
||||
git_commit_cmd
|
||||
.arg("-c")
|
||||
.arg("user.name=Dummy")
|
||||
.arg("-c")
|
||||
.arg("user.email=dummy@example.com")
|
||||
.arg("commit")
|
||||
.arg("-m")
|
||||
.arg("Initial commit")
|
||||
.arg("-q")
|
||||
.current_dir(repo_dir);
|
||||
let mut git_commit_cmd = git_command(repo_dir, "commit");
|
||||
git_commit_cmd.arg("-m").arg("Initial commit").arg("-q");
|
||||
spawn_and_wait(git_commit_cmd);
|
||||
}
|
||||
|
||||
|
|
@ -220,16 +207,8 @@ fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
|
|||
target_dir.file_name().unwrap(),
|
||||
patch.file_name().unwrap()
|
||||
);
|
||||
let mut apply_patch_cmd = Command::new("git");
|
||||
apply_patch_cmd
|
||||
.arg("-c")
|
||||
.arg("user.name=Dummy")
|
||||
.arg("-c")
|
||||
.arg("user.email=dummy@example.com")
|
||||
.arg("am")
|
||||
.arg(patch)
|
||||
.arg("-q")
|
||||
.current_dir(target_dir);
|
||||
let mut apply_patch_cmd = git_command(target_dir, "am");
|
||||
apply_patch_cmd.arg(patch).arg("-q");
|
||||
spawn_and_wait(apply_patch_cmd);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
pub(crate) fn get_rustc_version() -> String {
|
||||
pub(crate) fn get_rustc_version(rustc: &Path) -> String {
|
||||
let version_info =
|
||||
Command::new("rustc").stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
|
||||
Command::new(rustc).stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
|
||||
String::from_utf8(version_info).unwrap()
|
||||
}
|
||||
|
||||
|
|
@ -23,6 +23,16 @@ pub(crate) fn get_host_triple() -> String {
|
|||
.to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_toolchain_name() -> String {
|
||||
let active_toolchain = Command::new("rustup")
|
||||
.stderr(Stdio::inherit())
|
||||
.args(&["show", "active-toolchain"])
|
||||
.output()
|
||||
.unwrap()
|
||||
.stdout;
|
||||
String::from_utf8(active_toolchain).unwrap().trim().split_once(' ').unwrap().0.to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_cargo_path() -> PathBuf {
|
||||
let cargo_path = Command::new("rustup")
|
||||
.stderr(Stdio::inherit())
|
||||
|
|
@ -53,8 +63,8 @@ pub(crate) fn get_rustdoc_path() -> PathBuf {
|
|||
Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_default_sysroot() -> PathBuf {
|
||||
let default_sysroot = Command::new("rustc")
|
||||
pub(crate) fn get_default_sysroot(rustc: &Path) -> PathBuf {
|
||||
let default_sysroot = Command::new(rustc)
|
||||
.stderr(Stdio::inherit())
|
||||
.args(&["--print", "sysroot"])
|
||||
.output()
|
||||
|
|
@ -83,12 +93,3 @@ pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
|
|||
assert!(file_name.contains(crate_name));
|
||||
file_name
|
||||
}
|
||||
|
||||
/// Similar to `get_file_name`, but converts any dashes (`-`) in the `crate_name` to
|
||||
/// underscores (`_`). This is specially made for the rustc and cargo wrappers
|
||||
/// which have a dash in the name, and that is not allowed in a crate name.
|
||||
pub(crate) fn get_wrapper_file_name(crate_name: &str, crate_type: &str) -> String {
|
||||
let crate_name = crate_name.replace('-', "_");
|
||||
let wrapper_name = get_file_name(&crate_name, crate_type);
|
||||
wrapper_name.replace('_', "-")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use super::build_sysroot;
|
||||
use super::bench::SIMPLE_RAYTRACER;
|
||||
use super::build_sysroot::{self, SYSROOT_SRC};
|
||||
use super::config;
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::prepare::GitRepo;
|
||||
use super::rustc_info::{get_cargo_path, get_wrapper_file_name};
|
||||
use super::utils::{
|
||||
hyperfine_command, spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler,
|
||||
};
|
||||
use super::rustc_info::get_host_triple;
|
||||
use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler};
|
||||
use super::SysrootKind;
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
|
|
@ -17,256 +16,111 @@ static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
|
|||
|
||||
struct TestCase {
|
||||
config: &'static str,
|
||||
func: &'static dyn Fn(&TestRunner),
|
||||
cmd: TestCaseCmd,
|
||||
}
|
||||
|
||||
enum TestCaseCmd {
|
||||
Custom { func: &'static dyn Fn(&TestRunner) },
|
||||
BuildLib { source: &'static str, crate_types: &'static str },
|
||||
BuildBinAndRun { source: &'static str, args: &'static [&'static str] },
|
||||
JitBin { source: &'static str, args: &'static str },
|
||||
}
|
||||
|
||||
impl TestCase {
|
||||
const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
|
||||
Self { config, func }
|
||||
// FIXME reduce usage of custom test case commands
|
||||
const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
|
||||
Self { config, cmd: TestCaseCmd::Custom { func } }
|
||||
}
|
||||
|
||||
const fn build_lib(
|
||||
config: &'static str,
|
||||
source: &'static str,
|
||||
crate_types: &'static str,
|
||||
) -> Self {
|
||||
Self { config, cmd: TestCaseCmd::BuildLib { source, crate_types } }
|
||||
}
|
||||
|
||||
const fn build_bin_and_run(
|
||||
config: &'static str,
|
||||
source: &'static str,
|
||||
args: &'static [&'static str],
|
||||
) -> Self {
|
||||
Self { config, cmd: TestCaseCmd::BuildBinAndRun { source, args } }
|
||||
}
|
||||
|
||||
const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) -> Self {
|
||||
Self { config, cmd: TestCaseCmd::JitBin { source, args } }
|
||||
}
|
||||
}
|
||||
|
||||
const NO_SYSROOT_SUITE: &[TestCase] = &[
|
||||
TestCase::new("build.mini_core", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/mini_core.rs",
|
||||
"--crate-name",
|
||||
"mini_core",
|
||||
"--crate-type",
|
||||
"lib,dylib",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
}),
|
||||
TestCase::new("build.example", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/example.rs",
|
||||
"--crate-type",
|
||||
"lib",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
}),
|
||||
TestCase::new("jit.mini_core_hello_world", &|runner| {
|
||||
let mut jit_cmd = runner.rustc_command([
|
||||
"-Zunstable-options",
|
||||
"-Cllvm-args=mode=jit",
|
||||
"-Cprefer-dynamic",
|
||||
"example/mini_core_hello_world.rs",
|
||||
"--cfg",
|
||||
"jit",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
|
||||
spawn_and_wait(jit_cmd);
|
||||
|
||||
eprintln!("[JIT-lazy] mini_core_hello_world");
|
||||
let mut jit_cmd = runner.rustc_command([
|
||||
"-Zunstable-options",
|
||||
"-Cllvm-args=mode=jit-lazy",
|
||||
"-Cprefer-dynamic",
|
||||
"example/mini_core_hello_world.rs",
|
||||
"--cfg",
|
||||
"jit",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
|
||||
spawn_and_wait(jit_cmd);
|
||||
}),
|
||||
TestCase::new("aot.mini_core_hello_world", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/mini_core_hello_world.rs",
|
||||
"--crate-name",
|
||||
"mini_core_hello_world",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"-g",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
|
||||
}),
|
||||
TestCase::build_lib("build.mini_core", "example/mini_core.rs", "lib,dylib"),
|
||||
TestCase::build_lib("build.example", "example/example.rs", "lib"),
|
||||
TestCase::jit_bin("jit.mini_core_hello_world", "example/mini_core_hello_world.rs", "abc bcd"),
|
||||
TestCase::build_bin_and_run(
|
||||
"aot.mini_core_hello_world",
|
||||
"example/mini_core_hello_world.rs",
|
||||
&["abc", "bcd"],
|
||||
),
|
||||
];
|
||||
|
||||
const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
||||
TestCase::new("aot.arbitrary_self_types_pointers_and_wrappers", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/arbitrary_self_types_pointers_and_wrappers.rs",
|
||||
"--crate-name",
|
||||
"arbitrary_self_types_pointers_and_wrappers",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
|
||||
}),
|
||||
TestCase::new("aot.issue_91827_extern_types", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/issue-91827-extern-types.rs",
|
||||
"--crate-name",
|
||||
"issue_91827_extern_types",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("issue_91827_extern_types", []);
|
||||
}),
|
||||
TestCase::new("build.alloc_system", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/alloc_system.rs",
|
||||
"--crate-type",
|
||||
"lib",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
}),
|
||||
TestCase::new("aot.alloc_example", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/alloc_example.rs",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("alloc_example", []);
|
||||
}),
|
||||
TestCase::new("jit.std_example", &|runner| {
|
||||
runner.run_rustc([
|
||||
"-Zunstable-options",
|
||||
"-Cllvm-args=mode=jit",
|
||||
"-Cprefer-dynamic",
|
||||
"example/std_example.rs",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
|
||||
eprintln!("[JIT-lazy] std_example");
|
||||
runner.run_rustc([
|
||||
"-Zunstable-options",
|
||||
"-Cllvm-args=mode=jit-lazy",
|
||||
"-Cprefer-dynamic",
|
||||
"example/std_example.rs",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
}),
|
||||
TestCase::new("aot.std_example", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/std_example.rs",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("std_example", ["arg"]);
|
||||
}),
|
||||
TestCase::new("aot.dst_field_align", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/dst-field-align.rs",
|
||||
"--crate-name",
|
||||
"dst_field_align",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("dst_field_align", []);
|
||||
}),
|
||||
TestCase::new("aot.subslice-patterns-const-eval", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/subslice-patterns-const-eval.rs",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"-Cpanic=abort",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("subslice-patterns-const-eval", []);
|
||||
}),
|
||||
TestCase::new("aot.track-caller-attribute", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/track-caller-attribute.rs",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"-Cpanic=abort",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("track-caller-attribute", []);
|
||||
}),
|
||||
TestCase::new("aot.float-minmax-pass", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/float-minmax-pass.rs",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"-Cpanic=abort",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("float-minmax-pass", []);
|
||||
}),
|
||||
TestCase::new("aot.mod_bench", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/mod_bench.rs",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("mod_bench", []);
|
||||
}),
|
||||
TestCase::new("aot.issue-72793", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/issue-72793.rs",
|
||||
"--crate-type",
|
||||
"bin",
|
||||
"--target",
|
||||
&runner.target_compiler.triple,
|
||||
]);
|
||||
runner.run_out_command("issue-72793", []);
|
||||
}),
|
||||
TestCase::build_bin_and_run(
|
||||
"aot.arbitrary_self_types_pointers_and_wrappers",
|
||||
"example/arbitrary_self_types_pointers_and_wrappers.rs",
|
||||
&[],
|
||||
),
|
||||
TestCase::build_bin_and_run(
|
||||
"aot.issue_91827_extern_types",
|
||||
"example/issue-91827-extern-types.rs",
|
||||
&[],
|
||||
),
|
||||
TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
|
||||
TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
|
||||
TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""),
|
||||
TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
|
||||
TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
|
||||
TestCase::build_bin_and_run(
|
||||
"aot.subslice-patterns-const-eval",
|
||||
"example/subslice-patterns-const-eval.rs",
|
||||
&[],
|
||||
),
|
||||
TestCase::build_bin_and_run(
|
||||
"aot.track-caller-attribute",
|
||||
"example/track-caller-attribute.rs",
|
||||
&[],
|
||||
),
|
||||
TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]),
|
||||
TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
|
||||
TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
|
||||
];
|
||||
|
||||
pub(crate) static RAND_REPO: GitRepo =
|
||||
GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
|
||||
|
||||
static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
|
||||
pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
|
||||
|
||||
pub(crate) static REGEX_REPO: GitRepo =
|
||||
GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
|
||||
|
||||
static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex");
|
||||
pub(crate) static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex");
|
||||
|
||||
pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
|
||||
"rust-lang",
|
||||
"portable-simd",
|
||||
"d5cd4a8112d958bd3a252327e0d069a6363249bd",
|
||||
"582239ac3b32007613df04d7ffa78dc30f4c5645",
|
||||
"portable-simd",
|
||||
);
|
||||
|
||||
static PORTABLE_SIMD: CargoProject =
|
||||
pub(crate) static PORTABLE_SIMD: CargoProject =
|
||||
CargoProject::new(&PORTABLE_SIMD_REPO.source_dir(), "portable_simd");
|
||||
|
||||
pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
|
||||
"ebobby",
|
||||
"simple-raytracer",
|
||||
"804a7a21b9e673a482797aa289a18ed480e4d813",
|
||||
"<none>",
|
||||
);
|
||||
|
||||
pub(crate) static SIMPLE_RAYTRACER: CargoProject =
|
||||
CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
|
||||
|
||||
static LIBCORE_TESTS: CargoProject =
|
||||
CargoProject::new(&RelPath::BUILD_SYSROOT.join("sysroot_src/library/core/tests"), "core_tests");
|
||||
pub(crate) static LIBCORE_TESTS: CargoProject =
|
||||
CargoProject::new(&SYSROOT_SRC.join("library/core/tests"), "core_tests");
|
||||
|
||||
const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
||||
TestCase::new("test.rust-random/rand", &|runner| {
|
||||
spawn_and_wait(RAND.clean(&runner.target_compiler.cargo, &runner.dirs));
|
||||
TestCase::custom("test.rust-random/rand", &|runner| {
|
||||
RAND.clean(&runner.dirs);
|
||||
|
||||
if runner.is_native {
|
||||
eprintln!("[TEST] rust-random/rand");
|
||||
|
|
@ -280,60 +134,12 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
|||
spawn_and_wait(build_cmd);
|
||||
}
|
||||
}),
|
||||
TestCase::new("bench.simple-raytracer", &|runner| {
|
||||
let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
|
||||
|
||||
if runner.is_native {
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
|
||||
let cargo_clif = RelPath::DIST
|
||||
.to_path(&runner.dirs)
|
||||
.join(get_wrapper_file_name("cargo-clif", "bin"));
|
||||
let manifest_path = SIMPLE_RAYTRACER.manifest_path(&runner.dirs);
|
||||
let target_dir = SIMPLE_RAYTRACER.target_dir(&runner.dirs);
|
||||
|
||||
let clean_cmd = format!(
|
||||
"cargo clean --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
let llvm_build_cmd = format!(
|
||||
"cargo build --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
let clif_build_cmd = format!(
|
||||
"{cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir}",
|
||||
cargo_clif = cargo_clif.display(),
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
|
||||
let bench_compile =
|
||||
hyperfine_command(1, run_runs, Some(&clean_cmd), &llvm_build_cmd, &clif_build_cmd);
|
||||
|
||||
spawn_and_wait(bench_compile);
|
||||
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
|
||||
fs::copy(
|
||||
target_dir.join("debug").join("main"),
|
||||
RelPath::BUILD.to_path(&runner.dirs).join("raytracer_cg_clif"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut bench_run =
|
||||
hyperfine_command(0, run_runs, None, "./raytracer_cg_llvm", "./raytracer_cg_clif");
|
||||
bench_run.current_dir(RelPath::BUILD.to_path(&runner.dirs));
|
||||
spawn_and_wait(bench_run);
|
||||
} else {
|
||||
spawn_and_wait(SIMPLE_RAYTRACER.clean(&runner.target_compiler.cargo, &runner.dirs));
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
|
||||
eprintln!("[COMPILE] ebobby/simple-raytracer");
|
||||
spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
|
||||
}
|
||||
TestCase::custom("test.simple-raytracer", &|runner| {
|
||||
SIMPLE_RAYTRACER.clean(&runner.dirs);
|
||||
spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
|
||||
}),
|
||||
TestCase::new("test.libcore", &|runner| {
|
||||
spawn_and_wait(LIBCORE_TESTS.clean(&runner.host_compiler.cargo, &runner.dirs));
|
||||
TestCase::custom("test.libcore", &|runner| {
|
||||
LIBCORE_TESTS.clean(&runner.dirs);
|
||||
|
||||
if runner.is_native {
|
||||
spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
|
||||
|
|
@ -344,8 +150,8 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
|||
spawn_and_wait(build_cmd);
|
||||
}
|
||||
}),
|
||||
TestCase::new("test.regex-shootout-regex-dna", &|runner| {
|
||||
spawn_and_wait(REGEX.clean(&runner.target_compiler.cargo, &runner.dirs));
|
||||
TestCase::custom("test.regex-shootout-regex-dna", &|runner| {
|
||||
REGEX.clean(&runner.dirs);
|
||||
|
||||
// newer aho_corasick versions throw a deprecation warning
|
||||
let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
|
||||
|
|
@ -364,9 +170,10 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
|||
REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-input.txt"),
|
||||
)
|
||||
.unwrap();
|
||||
let expected_path =
|
||||
REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt");
|
||||
let expected = fs::read_to_string(&expected_path).unwrap();
|
||||
let expected = fs::read_to_string(
|
||||
REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let output = spawn_and_wait_with_input(run_cmd, input);
|
||||
// Make sure `[codegen mono items] start` doesn't poison the diff
|
||||
|
|
@ -379,27 +186,16 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
|||
|
||||
let output_matches = expected.lines().eq(output.lines());
|
||||
if !output_matches {
|
||||
let res_path = REGEX.source_dir(&runner.dirs).join("res.txt");
|
||||
fs::write(&res_path, &output).unwrap();
|
||||
|
||||
if cfg!(windows) {
|
||||
println!("Output files don't match!");
|
||||
println!("Expected Output:\n{}", expected);
|
||||
println!("Actual Output:\n{}", output);
|
||||
} else {
|
||||
let mut diff = Command::new("diff");
|
||||
diff.arg("-u");
|
||||
diff.arg(res_path);
|
||||
diff.arg(expected_path);
|
||||
spawn_and_wait(diff);
|
||||
}
|
||||
println!("Output files don't match!");
|
||||
println!("Expected Output:\n{}", expected);
|
||||
println!("Actual Output:\n{}", output);
|
||||
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}),
|
||||
TestCase::new("test.regex", &|runner| {
|
||||
spawn_and_wait(REGEX.clean(&runner.host_compiler.cargo, &runner.dirs));
|
||||
TestCase::custom("test.regex", &|runner| {
|
||||
REGEX.clean(&runner.dirs);
|
||||
|
||||
// newer aho_corasick versions throw a deprecation warning
|
||||
let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
|
||||
|
|
@ -425,8 +221,8 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
|
|||
spawn_and_wait(build_cmd);
|
||||
}
|
||||
}),
|
||||
TestCase::new("test.portable-simd", &|runner| {
|
||||
spawn_and_wait(PORTABLE_SIMD.clean(&runner.host_compiler.cargo, &runner.dirs));
|
||||
TestCase::custom("test.portable-simd", &|runner| {
|
||||
PORTABLE_SIMD.clean(&runner.dirs);
|
||||
|
||||
let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
|
||||
build_cmd.arg("--all-targets");
|
||||
|
|
@ -445,21 +241,22 @@ pub(crate) fn run_tests(
|
|||
channel: &str,
|
||||
sysroot_kind: SysrootKind,
|
||||
cg_clif_dylib: &Path,
|
||||
host_triple: &str,
|
||||
target_triple: &str,
|
||||
bootstrap_host_compiler: &Compiler,
|
||||
target_triple: String,
|
||||
) {
|
||||
let runner = TestRunner::new(dirs.clone(), host_triple.to_string(), target_triple.to_string());
|
||||
|
||||
if config::get_bool("testsuite.no_sysroot") {
|
||||
build_sysroot::build_sysroot(
|
||||
let target_compiler = build_sysroot::build_sysroot(
|
||||
dirs,
|
||||
channel,
|
||||
SysrootKind::None,
|
||||
cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
bootstrap_host_compiler,
|
||||
target_triple.clone(),
|
||||
);
|
||||
|
||||
let runner =
|
||||
TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
|
||||
|
||||
BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
|
||||
runner.run_testsuite(NO_SYSROOT_SUITE);
|
||||
} else {
|
||||
|
|
@ -470,26 +267,29 @@ pub(crate) fn run_tests(
|
|||
let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
|
||||
|
||||
if run_base_sysroot || run_extended_sysroot {
|
||||
build_sysroot::build_sysroot(
|
||||
let target_compiler = build_sysroot::build_sysroot(
|
||||
dirs,
|
||||
channel,
|
||||
sysroot_kind,
|
||||
cg_clif_dylib,
|
||||
&host_triple,
|
||||
&target_triple,
|
||||
bootstrap_host_compiler,
|
||||
target_triple.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
if run_base_sysroot {
|
||||
runner.run_testsuite(BASE_SYSROOT_SUITE);
|
||||
} else {
|
||||
eprintln!("[SKIP] base_sysroot tests");
|
||||
}
|
||||
let runner =
|
||||
TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
|
||||
|
||||
if run_extended_sysroot {
|
||||
runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
|
||||
} else {
|
||||
eprintln!("[SKIP] extended_sysroot tests");
|
||||
if run_base_sysroot {
|
||||
runner.run_testsuite(BASE_SYSROOT_SUITE);
|
||||
} else {
|
||||
eprintln!("[SKIP] base_sysroot tests");
|
||||
}
|
||||
|
||||
if run_extended_sysroot {
|
||||
runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
|
||||
} else {
|
||||
eprintln!("[SKIP] extended_sysroot tests");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -497,84 +297,34 @@ struct TestRunner {
|
|||
is_native: bool,
|
||||
jit_supported: bool,
|
||||
dirs: Dirs,
|
||||
host_compiler: Compiler,
|
||||
target_compiler: Compiler,
|
||||
}
|
||||
|
||||
impl TestRunner {
|
||||
pub fn new(dirs: Dirs, host_triple: String, target_triple: String) -> Self {
|
||||
let is_native = host_triple == target_triple;
|
||||
let jit_supported =
|
||||
target_triple.contains("x86_64") && is_native && !host_triple.contains("windows");
|
||||
|
||||
let rustc_clif =
|
||||
RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustc-clif", "bin"));
|
||||
let rustdoc_clif =
|
||||
RelPath::DIST.to_path(&dirs).join(get_wrapper_file_name("rustdoc-clif", "bin"));
|
||||
|
||||
let mut rustflags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
|
||||
let mut runner = vec![];
|
||||
|
||||
if !is_native {
|
||||
match target_triple.as_str() {
|
||||
"aarch64-unknown-linux-gnu" => {
|
||||
// We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
|
||||
rustflags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rustflags);
|
||||
runner = vec![
|
||||
"qemu-aarch64".to_owned(),
|
||||
"-L".to_owned(),
|
||||
"/usr/aarch64-linux-gnu".to_owned(),
|
||||
];
|
||||
}
|
||||
"s390x-unknown-linux-gnu" => {
|
||||
// We are cross-compiling for s390x. Use the correct linker and run tests in qemu.
|
||||
rustflags = format!("-Clinker=s390x-linux-gnu-gcc{}", rustflags);
|
||||
runner = vec![
|
||||
"qemu-s390x".to_owned(),
|
||||
"-L".to_owned(),
|
||||
"/usr/s390x-linux-gnu".to_owned(),
|
||||
];
|
||||
}
|
||||
"x86_64-pc-windows-gnu" => {
|
||||
// We are cross-compiling for Windows. Run tests in wine.
|
||||
runner = vec!["wine".to_owned()];
|
||||
}
|
||||
_ => {
|
||||
println!("Unknown non-native platform");
|
||||
}
|
||||
}
|
||||
pub fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
|
||||
if let Ok(rustflags) = env::var("RUSTFLAGS") {
|
||||
target_compiler.rustflags.push(' ');
|
||||
target_compiler.rustflags.push_str(&rustflags);
|
||||
}
|
||||
if let Ok(rustdocflags) = env::var("RUSTDOCFLAGS") {
|
||||
target_compiler.rustdocflags.push(' ');
|
||||
target_compiler.rustdocflags.push_str(&rustdocflags);
|
||||
}
|
||||
|
||||
// FIXME fix `#[linkage = "extern_weak"]` without this
|
||||
if target_triple.contains("darwin") {
|
||||
rustflags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rustflags);
|
||||
if target_compiler.triple.contains("darwin") {
|
||||
target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup");
|
||||
}
|
||||
|
||||
let host_compiler = Compiler {
|
||||
cargo: get_cargo_path(),
|
||||
rustc: rustc_clif.clone(),
|
||||
rustdoc: rustdoc_clif.clone(),
|
||||
rustflags: String::new(),
|
||||
rustdocflags: String::new(),
|
||||
triple: host_triple,
|
||||
runner: vec![],
|
||||
};
|
||||
let jit_supported = is_native
|
||||
&& target_compiler.triple.contains("x86_64")
|
||||
&& !target_compiler.triple.contains("windows");
|
||||
|
||||
let target_compiler = Compiler {
|
||||
cargo: get_cargo_path(),
|
||||
rustc: rustc_clif,
|
||||
rustdoc: rustdoc_clif,
|
||||
rustflags: rustflags.clone(),
|
||||
rustdocflags: rustflags,
|
||||
triple: target_triple,
|
||||
runner,
|
||||
};
|
||||
|
||||
Self { is_native, jit_supported, dirs, host_compiler, target_compiler }
|
||||
Self { is_native, jit_supported, dirs, target_compiler }
|
||||
}
|
||||
|
||||
pub fn run_testsuite(&self, tests: &[TestCase]) {
|
||||
for &TestCase { config, func } in tests {
|
||||
for TestCase { config, cmd } in tests {
|
||||
let (tag, testname) = config.split_once('.').unwrap();
|
||||
let tag = tag.to_uppercase();
|
||||
let is_jit_test = tag == "JIT";
|
||||
|
|
@ -586,7 +336,47 @@ impl TestRunner {
|
|||
eprintln!("[{tag}] {testname}");
|
||||
}
|
||||
|
||||
func(self);
|
||||
match *cmd {
|
||||
TestCaseCmd::Custom { func } => func(self),
|
||||
TestCaseCmd::BuildLib { source, crate_types } => {
|
||||
self.run_rustc([source, "--crate-type", crate_types]);
|
||||
}
|
||||
TestCaseCmd::BuildBinAndRun { source, args } => {
|
||||
self.run_rustc([source]);
|
||||
self.run_out_command(
|
||||
source.split('/').last().unwrap().split('.').next().unwrap(),
|
||||
args,
|
||||
);
|
||||
}
|
||||
TestCaseCmd::JitBin { source, args } => {
|
||||
let mut jit_cmd = self.rustc_command([
|
||||
"-Zunstable-options",
|
||||
"-Cllvm-args=mode=jit",
|
||||
"-Cprefer-dynamic",
|
||||
source,
|
||||
"--cfg",
|
||||
"jit",
|
||||
]);
|
||||
if !args.is_empty() {
|
||||
jit_cmd.env("CG_CLIF_JIT_ARGS", args);
|
||||
}
|
||||
spawn_and_wait(jit_cmd);
|
||||
|
||||
eprintln!("[JIT-lazy] {testname}");
|
||||
let mut jit_cmd = self.rustc_command([
|
||||
"-Zunstable-options",
|
||||
"-Cllvm-args=mode=jit-lazy",
|
||||
"-Cprefer-dynamic",
|
||||
source,
|
||||
"--cfg",
|
||||
"jit",
|
||||
]);
|
||||
if !args.is_empty() {
|
||||
jit_cmd.env("CG_CLIF_JIT_ARGS", args);
|
||||
}
|
||||
spawn_and_wait(jit_cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -603,6 +393,9 @@ impl TestRunner {
|
|||
cmd.arg("--out-dir");
|
||||
cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
|
||||
cmd.arg("-Cdebuginfo=2");
|
||||
cmd.arg("--target");
|
||||
cmd.arg(&self.target_compiler.triple);
|
||||
cmd.arg("-Cpanic=abort");
|
||||
cmd.args(args);
|
||||
cmd
|
||||
}
|
||||
|
|
@ -615,10 +408,7 @@ impl TestRunner {
|
|||
spawn_and_wait(self.rustc_command(args));
|
||||
}
|
||||
|
||||
fn run_out_command<'a, I>(&self, name: &str, args: I)
|
||||
where
|
||||
I: IntoIterator<Item = &'a str>,
|
||||
{
|
||||
fn run_out_command<'a>(&self, name: &str, args: &[&str]) {
|
||||
let mut full_cmd = vec![];
|
||||
|
||||
// Prepend the RUN_WRAPPER's
|
||||
|
|
@ -630,7 +420,7 @@ impl TestRunner {
|
|||
BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
|
||||
);
|
||||
|
||||
for arg in args.into_iter() {
|
||||
for arg in args {
|
||||
full_cmd.push(arg.to_string());
|
||||
}
|
||||
|
||||
|
|
|
|||
35
compiler/rustc_codegen_cranelift/build_system/usage.txt
Normal file
35
compiler/rustc_codegen_cranelift/build_system/usage.txt
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
The build system of cg_clif.
|
||||
|
||||
USAGE:
|
||||
./y.rs prepare [--out-dir DIR]
|
||||
./y.rs build [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
|
||||
./y.rs test [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
|
||||
./y.rs abi-cafe [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
|
||||
./y.rs bench [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
|
||||
|
||||
OPTIONS:
|
||||
--debug
|
||||
Build cg_clif and the standard library in debug mode rather than release mode.
|
||||
Warning: An unoptimized cg_clif is very slow.
|
||||
|
||||
--sysroot none|clif|llvm
|
||||
Which sysroot libraries to use:
|
||||
`none` will not include any standard library in the sysroot.
|
||||
`clif` will build the standard library using Cranelift.
|
||||
`llvm` will use the pre-compiled standard library of rustc which is compiled with LLVM.
|
||||
|
||||
--out-dir DIR
|
||||
Specify the directory in which the download, build and dist directories are stored.
|
||||
By default this is the working directory.
|
||||
|
||||
--no-unstable-features
|
||||
Some features are not yet ready for production usage. This option will disable these
|
||||
features. This includes the JIT mode and inline assembly support.
|
||||
|
||||
REQUIREMENTS:
|
||||
* Rustup: The build system has a hard coded dependency on rustup to install the right nightly
|
||||
version and make sure it is used where necessary.
|
||||
* Git: `./y.rs prepare` uses git for applying patches and on Windows for downloading test repos.
|
||||
* Curl and tar (non-Windows only): Used by `./y.rs prepare` to download a single commit for
|
||||
repos. Git will be used to clone the whole repo when using Windows.
|
||||
* [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.rs bench`.
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, Command, Stdio};
|
||||
|
||||
use super::path::{Dirs, RelPath};
|
||||
use super::rustc_info::{get_cargo_path, get_host_triple, get_rustc_path, get_rustdoc_path};
|
||||
use super::rustc_info::{get_cargo_path, get_rustc_path, get_rustdoc_path};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Compiler {
|
||||
pub(crate) cargo: PathBuf,
|
||||
pub(crate) rustc: PathBuf,
|
||||
|
|
@ -18,19 +19,7 @@ pub(crate) struct Compiler {
|
|||
}
|
||||
|
||||
impl Compiler {
|
||||
pub(crate) fn host() -> Compiler {
|
||||
Compiler {
|
||||
cargo: get_cargo_path(),
|
||||
rustc: get_rustc_path(),
|
||||
rustdoc: get_rustdoc_path(),
|
||||
rustflags: String::new(),
|
||||
rustdocflags: String::new(),
|
||||
triple: get_host_triple(),
|
||||
runner: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_triple(triple: String) -> Compiler {
|
||||
pub(crate) fn bootstrap_with_triple(triple: String) -> Compiler {
|
||||
Compiler {
|
||||
cargo: get_cargo_path(),
|
||||
rustc: get_rustc_path(),
|
||||
|
|
@ -41,6 +30,38 @@ impl Compiler {
|
|||
runner: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_cross_linker_and_runner(&mut self) {
|
||||
match self.triple.as_str() {
|
||||
"aarch64-unknown-linux-gnu" => {
|
||||
// We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
|
||||
self.rustflags += " -Clinker=aarch64-linux-gnu-gcc";
|
||||
self.rustdocflags += " -Clinker=aarch64-linux-gnu-gcc";
|
||||
self.runner = vec![
|
||||
"qemu-aarch64".to_owned(),
|
||||
"-L".to_owned(),
|
||||
"/usr/aarch64-linux-gnu".to_owned(),
|
||||
];
|
||||
}
|
||||
"s390x-unknown-linux-gnu" => {
|
||||
// We are cross-compiling for s390x. Use the correct linker and run tests in qemu.
|
||||
self.rustflags += " -Clinker=s390x-linux-gnu-gcc";
|
||||
self.rustdocflags += " -Clinker=s390x-linux-gnu-gcc";
|
||||
self.runner = vec![
|
||||
"qemu-s390x".to_owned(),
|
||||
"-L".to_owned(),
|
||||
"/usr/s390x-linux-gnu".to_owned(),
|
||||
];
|
||||
}
|
||||
"x86_64-pc-windows-gnu" => {
|
||||
// We are cross-compiling for Windows. Run tests in wine.
|
||||
self.runner = vec!["wine".to_owned()];
|
||||
}
|
||||
_ => {
|
||||
println!("Unknown non-native platform");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CargoProject {
|
||||
|
|
@ -65,6 +86,7 @@ impl CargoProject {
|
|||
RelPath::BUILD.join(self.target).to_path(dirs)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
|
||||
let mut cmd = Command::new(cargo);
|
||||
|
||||
|
|
@ -72,11 +94,13 @@ impl CargoProject {
|
|||
.arg("--manifest-path")
|
||||
.arg(self.manifest_path(dirs))
|
||||
.arg("--target-dir")
|
||||
.arg(self.target_dir(dirs));
|
||||
.arg(self.target_dir(dirs))
|
||||
.arg("--frozen");
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command {
|
||||
let mut cmd = self.base_cmd(command, &compiler.cargo, dirs);
|
||||
|
||||
|
|
@ -105,9 +129,8 @@ impl CargoProject {
|
|||
cmd
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn clean(&self, cargo: &Path, dirs: &Dirs) -> Command {
|
||||
self.base_cmd("clean", cargo, dirs)
|
||||
pub(crate) fn clean(&self, dirs: &Dirs) {
|
||||
let _ = fs::remove_dir_all(self.target_dir(dirs));
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
@ -153,6 +176,23 @@ pub(crate) fn hyperfine_command(
|
|||
bench
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn git_command<'a>(repo_dir: impl Into<Option<&'a Path>>, cmd: &str) -> Command {
|
||||
let mut git_cmd = Command::new("git");
|
||||
git_cmd
|
||||
.arg("-c")
|
||||
.arg("user.name=Dummy")
|
||||
.arg("-c")
|
||||
.arg("user.email=dummy@example.com")
|
||||
.arg("-c")
|
||||
.arg("core.autocrlf=false")
|
||||
.arg(cmd);
|
||||
if let Some(repo_dir) = repo_dir.into() {
|
||||
git_cmd.current_dir(repo_dir);
|
||||
}
|
||||
git_cmd
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
|
||||
let src = src.as_ref();
|
||||
|
|
@ -169,6 +209,22 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) {
|
|||
}
|
||||
}
|
||||
|
||||
// Based on the retry function in rust's src/ci/shared.sh
|
||||
#[track_caller]
|
||||
pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) {
|
||||
for i in 1..tries + 1 {
|
||||
if i != 1 {
|
||||
println!("Command failed. Attempt {i}/{tries}:");
|
||||
}
|
||||
if cmd.spawn().unwrap().wait().unwrap().success() {
|
||||
return;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_secs(i * 5));
|
||||
}
|
||||
println!("The command has failed after {tries} attempts.");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> String {
|
||||
let mut child = cmd
|
||||
|
|
@ -190,6 +246,14 @@ pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> Stri
|
|||
String::from_utf8(output.stdout).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn remove_dir_if_exists(path: &Path) {
|
||||
match fs::remove_dir_all(&path) {
|
||||
Ok(()) => {}
|
||||
Err(err) if err.kind() == io::ErrorKind::NotFound => {}
|
||||
Err(err) => panic!("Failed to remove {path}: {err}", path = path.display()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {
|
||||
for entry in fs::read_dir(from).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
|
||||
rm -rf target/ build/ dist/ perf.data{,.old} y.bin
|
||||
rm -rf download/
|
||||
rm -rf target/ download/ build/ dist/ y.bin y.bin.dSYM y.exe y.pdb
|
||||
|
||||
# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
|
||||
# FIXME remove at some point in the future
|
||||
rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/
|
||||
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
|
||||
|
|
|
|||
|
|
@ -44,10 +44,8 @@ aot.issue-72793
|
|||
|
||||
testsuite.extended_sysroot
|
||||
test.rust-random/rand
|
||||
bench.simple-raytracer
|
||||
test.simple-raytracer
|
||||
test.libcore
|
||||
test.regex-shootout-regex-dna
|
||||
test.regex
|
||||
test.portable-simd
|
||||
|
||||
testsuite.abi-cafe
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
From b742f03694b920cc14400727d54424e8e1b60928 Mon Sep 17 00:00:00 2001
|
||||
From: bjorn3 <bjorn3@users.noreply.github.com>
|
||||
Date: Thu, 18 Nov 2021 19:28:40 +0100
|
||||
Subject: [PATCH] Disable unsupported tests
|
||||
|
||||
---
|
||||
crates/core_simd/src/elements/int.rs | 8 ++++++++
|
||||
crates/core_simd/src/elements/uint.rs | 4 ++++
|
||||
crates/core_simd/src/masks/full_masks.rs | 6 ++++++
|
||||
crates/core_simd/src/vector.rs | 2 ++
|
||||
crates/core_simd/tests/masks.rs | 3 ---
|
||||
5 files changed, 20 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
|
||||
index e8e8f68..7173c24 100644
|
||||
--- a/crates/core_simd/src/vector.rs
|
||||
+++ b/crates/core_simd/src/vector.rs
|
||||
@@ -250,6 +250,7 @@ where
|
||||
unsafe { intrinsics::simd_cast(self) }
|
||||
}
|
||||
|
||||
+ /*
|
||||
/// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
|
||||
/// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
|
||||
///
|
||||
@@ -473,6 +474,7 @@ where
|
||||
// Cleared ☢️ *mut T Zone
|
||||
}
|
||||
}
|
||||
+ */
|
||||
}
|
||||
|
||||
impl<T, const LANES: usize> Copy for Simd<T, LANES>
|
||||
--
|
||||
2.25.1
|
||||
|
|
@ -18,7 +18,7 @@ new file mode 100644
|
|||
index 0000000..46fd999
|
||||
--- /dev/null
|
||||
+++ b/library/core/tests/Cargo.toml
|
||||
@@ -0,0 +1,11 @@
|
||||
@@ -0,0 +1,12 @@
|
||||
+[package]
|
||||
+name = "core"
|
||||
+version = "0.0.0"
|
||||
|
|
@ -29,6 +29,7 @@ index 0000000..46fd999
|
|||
+path = "lib.rs"
|
||||
+
|
||||
+[dependencies]
|
||||
+rand = "0.7"
|
||||
+rand = { version = "0.8.5", default-features = false }
|
||||
+rand_xorshift = { version = "0.3.0", default-features = false }
|
||||
--
|
||||
2.21.0 (Apple Git-122)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2022-12-13"
|
||||
channel = "nightly-2023-01-20"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn main() {
|
|||
env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags);
|
||||
|
||||
// Ensure that the right toolchain is used
|
||||
env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
|
||||
env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
|
||||
|
||||
let args: Vec<_> = match env::args().nth(1).as_deref() {
|
||||
Some("jit") => {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ fn main() {
|
|||
}
|
||||
|
||||
// Ensure that the right toolchain is used
|
||||
env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
|
||||
env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
|
||||
|
||||
#[cfg(unix)]
|
||||
Command::new("rustc").args(args).exec();
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ fn main() {
|
|||
}
|
||||
|
||||
// Ensure that the right toolchain is used
|
||||
env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
|
||||
env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
|
||||
|
||||
#[cfg(unix)]
|
||||
Command::new("rustdoc").args(args).exec();
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ case $1 in
|
|||
done
|
||||
|
||||
./clean_all.sh
|
||||
|
||||
./y.rs prepare
|
||||
|
||||
(cd build_sysroot && cargo update)
|
||||
|
||||
(cd download/sysroot && cargo update && cargo fetch && cp Cargo.lock ../../build_sysroot/)
|
||||
;;
|
||||
"commit")
|
||||
git add rust-toolchain build_sysroot/Cargo.lock
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ git fetch
|
|||
git checkout -- .
|
||||
git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
|
||||
|
||||
git am ../patches/*-sysroot-*.patch
|
||||
git -c user.name=Dummy -c user.email=dummy@example.com am ../patches/*-sysroot-*.patch
|
||||
|
||||
git apply - <<EOF
|
||||
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
|
||||
|
|
@ -25,8 +25,8 @@ index d95b5b7f17f..00b6f0e3635 100644
|
|||
+compiler_builtins = { version = "0.1.66", features = ['rustc-dep-of-std', 'no-asm'] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7"
|
||||
rand_xorshift = "0.2"
|
||||
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
|
||||
rand_xorshift = "0.3.0"
|
||||
EOF
|
||||
|
||||
cat > config.toml <<EOF
|
||||
|
|
@ -51,7 +51,7 @@ popd
|
|||
# FIXME remove once inline asm is fully supported
|
||||
export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
|
||||
|
||||
export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd build_sysroot/sysroot_src; pwd)"
|
||||
export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd download/sysroot/sysroot_src; pwd)"
|
||||
|
||||
# Allow the testsuite to use llvm tools
|
||||
host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pushd rust
|
|||
command -v rg >/dev/null 2>&1 || cargo install ripgrep
|
||||
|
||||
rm -r tests/ui/{extern/,unsized-locals/,lto/,linkage*} || true
|
||||
for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{ui,incremental}); do
|
||||
for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{codegen-units,ui,incremental}); do
|
||||
rm $test
|
||||
done
|
||||
|
||||
|
|
@ -32,20 +32,13 @@ rm tests/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort
|
|||
# requires compiling with -Cpanic=unwind
|
||||
rm -r tests/ui/macros/rfc-2011-nicer-assert-messages/
|
||||
rm -r tests/run-make/test-benches
|
||||
rm tests/ui/test-attrs/test-type.rs
|
||||
|
||||
# vendor intrinsics
|
||||
rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected
|
||||
rm tests/ui/intrinsics/const-eval-select-x86_64.rs # requires x86_64 vendor intrinsics
|
||||
rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
|
||||
rm tests/ui/simd/intrinsic/generic-bitmask-pass.rs # simd_bitmask unimplemented
|
||||
rm tests/ui/simd/intrinsic/generic-as.rs # simd_as unimplemented
|
||||
rm tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs # simd_saturating_add unimplemented
|
||||
rm tests/ui/simd/intrinsic/float-math-pass.rs # simd_fcos unimplemented
|
||||
rm tests/ui/simd/intrinsic/generic-gather-pass.rs # simd_gather unimplemented
|
||||
rm tests/ui/simd/intrinsic/generic-select-pass.rs # simd_select_bitmask unimplemented
|
||||
rm tests/ui/simd/issue-85915-simd-ptrs.rs # simd_gather unimplemented
|
||||
rm tests/ui/simd/issue-89193.rs # simd_gather unimplemented
|
||||
rm tests/ui/simd/simd-bitmask.rs # simd_bitmask unimplemented
|
||||
|
||||
# exotic linkages
|
||||
rm tests/ui/issues/issue-33992.rs # unsupported linkages
|
||||
|
|
@ -64,10 +57,7 @@ rm tests/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and near
|
|||
rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
|
||||
rm tests/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
|
||||
rm -r tests/run-make/emit-named-files # requires full --emit support
|
||||
rm tests/ui/abi/stack-probes.rs # stack probes not yet implemented
|
||||
rm tests/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
|
||||
rm -r tests/run-make/repr128-dwarf # debuginfo test
|
||||
rm tests/codegen-units/item-collection/asm-sym.rs # requires support for sym in asm!()
|
||||
|
||||
# optimization tests
|
||||
# ==================
|
||||
|
|
@ -88,6 +78,20 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same
|
|||
rm tests/ui/consts/issue-33537.rs # same
|
||||
rm tests/ui/layout/valid_range_oob.rs # different ICE message
|
||||
|
||||
rm tests/ui/consts/issue-miri-1910.rs # different error message
|
||||
rm tests/ui/consts/offset_ub.rs # same
|
||||
rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same
|
||||
rm tests/ui/lint/lint-const-item-mutation.rs # same
|
||||
rm tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs # same
|
||||
rm tests/ui/suggestions/derive-trait-for-method-call.rs # same
|
||||
rm tests/ui/typeck/issue-46112.rs # same
|
||||
|
||||
rm tests/ui/proc-macro/crt-static.rs # extra warning about -Cpanic=abort for proc macros
|
||||
rm tests/ui/proc-macro/proc-macro-deprecated-attr.rs # same
|
||||
rm tests/ui/proc-macro/quote-debug.rs # same
|
||||
rm tests/ui/proc-macro/no-missing-docs.rs # same
|
||||
rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs # same
|
||||
|
||||
# doesn't work due to the way the rustc test suite is invoked.
|
||||
# should work when using ./x.py test the way it is intended
|
||||
# ============================================================
|
||||
|
|
@ -102,23 +106,20 @@ rm -r tests/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to b
|
|||
# ============
|
||||
rm tests/incremental/spike-neg1.rs # errors out for some reason
|
||||
rm tests/incremental/spike-neg2.rs # same
|
||||
rm tests/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
|
||||
rm tests/ui/mir/ssa-analysis-regression-50041.rs # produces ICE
|
||||
rm tests/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE
|
||||
|
||||
rm tests/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
|
||||
|
||||
rm tests/ui/runtime/out-of-stack.rs # SIGSEGV instead of SIGABRT for some reason (#1301)
|
||||
rm tests/ui/simd/intrinsic/generic-as.rs # crash when accessing vector type filed (#1318)
|
||||
rm tests/ui/simd/simd-bitmask.rs # crash
|
||||
|
||||
rm tests/ui/dyn-star/dyn-star-to-dyn.rs
|
||||
rm tests/ui/dyn-star/dispatch-on-pin-mut.rs
|
||||
|
||||
# bugs in the test suite
|
||||
# ======================
|
||||
rm tests/ui/backtrace.rs # TODO warning
|
||||
rm tests/ui/simple_global_asm.rs # TODO add needs-asm-support
|
||||
rm tests/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
|
||||
# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
|
||||
rm -r tests/run-make/native-link-modifier-bundle
|
||||
rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
|
||||
rm tests/ui/dyn-star/dispatch-on-pin-mut.rs # TODO failed assertion in vtable::get_ptr_and_method_ref
|
||||
|
||||
rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ mod returning;
|
|||
use cranelift_module::ModuleError;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::abi::call::{Conv, FnAbi};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ fn clif_sig_from_fn_abi<'tcx>(
|
|||
default_call_conv: CallConv,
|
||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
) -> Signature {
|
||||
let call_conv = conv_to_call_conv(fn_abi.conv, default_call_conv);
|
||||
let call_conv = conv_to_call_conv(tcx.sess, fn_abi.conv, default_call_conv);
|
||||
|
||||
let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten();
|
||||
|
||||
|
|
@ -33,24 +34,32 @@ fn clif_sig_from_fn_abi<'tcx>(
|
|||
Signature { params, returns, call_conv }
|
||||
}
|
||||
|
||||
pub(crate) fn conv_to_call_conv(c: Conv, default_call_conv: CallConv) -> CallConv {
|
||||
pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv {
|
||||
match c {
|
||||
Conv::Rust | Conv::C => default_call_conv,
|
||||
Conv::RustCold => CallConv::Cold,
|
||||
Conv::X86_64SysV => CallConv::SystemV,
|
||||
Conv::X86_64Win64 => CallConv::WindowsFastcall,
|
||||
Conv::ArmAapcs
|
||||
| Conv::CCmseNonSecureCall
|
||||
| Conv::Msp430Intr
|
||||
|
||||
// Should already get a back compat warning
|
||||
Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => {
|
||||
default_call_conv
|
||||
}
|
||||
|
||||
Conv::X86Intr => sess.fatal("x86-interrupt call conv not yet implemented"),
|
||||
|
||||
Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"),
|
||||
Conv::CCmseNonSecureCall => {
|
||||
sess.fatal("C-cmse-nonsecure-call call conv is not yet implemented");
|
||||
}
|
||||
|
||||
Conv::Msp430Intr
|
||||
| Conv::PtxKernel
|
||||
| Conv::X86Fastcall
|
||||
| Conv::X86Intr
|
||||
| Conv::X86Stdcall
|
||||
| Conv::X86ThisCall
|
||||
| Conv::X86VectorCall
|
||||
| Conv::AmdGpuKernel
|
||||
| Conv::AvrInterrupt
|
||||
| Conv::AvrNonBlockingInterrupt => todo!("{:?}", c),
|
||||
| Conv::AvrNonBlockingInterrupt => {
|
||||
unreachable!("tried to use {c:?} call conv which only exists on an unsupported target");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +170,12 @@ fn make_local_place<'tcx>(
|
|||
layout: TyAndLayout<'tcx>,
|
||||
is_ssa: bool,
|
||||
) -> CPlace<'tcx> {
|
||||
if layout.is_unsized() {
|
||||
fx.tcx.sess.span_fatal(
|
||||
fx.mir.local_decls[local].source_info.span,
|
||||
"unsized locals are not yet supported",
|
||||
);
|
||||
}
|
||||
let place = if is_ssa {
|
||||
if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi {
|
||||
CPlace::new_var_pair(fx, local, layout)
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ pub(crate) fn codegen_fn<'tcx>(
|
|||
};
|
||||
|
||||
tcx.sess.time("codegen clif ir", || codegen_fn_body(&mut fx, start_block));
|
||||
fx.bcx.seal_all_blocks();
|
||||
fx.bcx.finalize();
|
||||
|
||||
// Recover all necessary data from fx, before accessing func will prevent future access to it.
|
||||
let symbol_name = fx.symbol_name;
|
||||
|
|
@ -303,6 +305,9 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
let source_info = bb_data.terminator().source_info;
|
||||
fx.set_debug_loc(source_info);
|
||||
|
||||
let _print_guard =
|
||||
crate::PrintOnPanic(|| format!("terminator {:?}", bb_data.terminator().kind));
|
||||
|
||||
match &bb_data.terminator().kind {
|
||||
TerminatorKind::Goto { target } => {
|
||||
if let TerminatorKind::Return = fx.mir[*target].terminator().kind {
|
||||
|
|
@ -464,7 +469,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
*destination,
|
||||
);
|
||||
}
|
||||
TerminatorKind::Resume | TerminatorKind::Abort => {
|
||||
TerminatorKind::Abort => {
|
||||
codegen_panic_cannot_unwind(fx, source_info);
|
||||
}
|
||||
TerminatorKind::Resume => {
|
||||
// FIXME implement unwinding
|
||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
||||
}
|
||||
|
|
@ -487,9 +495,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
fx.bcx.seal_all_blocks();
|
||||
fx.bcx.finalize();
|
||||
}
|
||||
|
||||
fn codegen_stmt<'tcx>(
|
||||
|
|
@ -789,6 +794,7 @@ fn codegen_stmt<'tcx>(
|
|||
StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::Deinit(_)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop
|
||||
| StatementKind::FakeRead(..)
|
||||
| StatementKind::Retag { .. }
|
||||
|
|
@ -932,7 +938,28 @@ pub(crate) fn codegen_panic<'tcx>(
|
|||
codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span);
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_panic_inner<'tcx>(
|
||||
pub(crate) fn codegen_panic_nounwind<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
msg_str: &str,
|
||||
source_info: mir::SourceInfo,
|
||||
) {
|
||||
let msg_ptr = fx.anonymous_str(msg_str);
|
||||
let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
|
||||
let args = [msg_ptr, msg_len];
|
||||
|
||||
codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span);
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_panic_cannot_unwind<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
source_info: mir::SourceInfo,
|
||||
) {
|
||||
let args = [];
|
||||
|
||||
codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span);
|
||||
}
|
||||
|
||||
fn codegen_panic_inner<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
lang_item: rustc_hir::LangItem,
|
||||
args: &[Value],
|
||||
|
|
@ -949,11 +976,7 @@ pub(crate) fn codegen_panic_inner<'tcx>(
|
|||
|
||||
fx.lib_call(
|
||||
&*symbol_name,
|
||||
vec![
|
||||
AbiParam::new(fx.pointer_type),
|
||||
AbiParam::new(fx.pointer_type),
|
||||
AbiParam::new(fx.pointer_type),
|
||||
],
|
||||
args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(),
|
||||
vec![],
|
||||
args,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,8 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
|
|||
},
|
||||
Primitive::F32 => types::F32,
|
||||
Primitive::F64 => types::F64,
|
||||
Primitive::Pointer => pointer_ty(tcx),
|
||||
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
|
||||
Primitive::Pointer(_) => pointer_ty(tcx),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,6 +168,15 @@ pub(crate) fn codegen_icmp_imm(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value {
|
||||
let mut flags = MemFlags::new();
|
||||
flags.set_endianness(match fx.tcx.data_layout.endian {
|
||||
rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
|
||||
rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
|
||||
});
|
||||
fx.bcx.ins().bitcast(dst_ty, flags, val)
|
||||
}
|
||||
|
||||
pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value {
|
||||
if ty == types::I128 {
|
||||
let zero = bcx.ins().iconst(types::I64, 0);
|
||||
|
|
|
|||
|
|
@ -530,6 +530,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
|||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::AscribeUserType(_, _)
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::ConstEvalCounter
|
||||
| StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
248
compiler/rustc_codegen_cranelift/src/cranelift_native.rs
Normal file
248
compiler/rustc_codegen_cranelift/src/cranelift_native.rs
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
// Vendored from https://github.com/bytecodealliance/wasmtime/blob/b58a197d33f044193c3d608010f5e6ec394ac07e/cranelift/native/src/lib.rs
|
||||
// which is licensed as
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
// unlike rustc_codegen_cranelift itself. Also applies a small change to remove #![cfg_attr] that
|
||||
// rust's CI complains about and to fix formatting to match rustc.
|
||||
// FIXME revert back to the external crate with Cranelift 0.93
|
||||
#![allow(warnings)]
|
||||
|
||||
//! Performs autodetection of the host for the purposes of running
|
||||
//! Cranelift to generate code to run on the same machine.
|
||||
|
||||
#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates, unstable_features)]
|
||||
#![warn(unused_import_braces)]
|
||||
|
||||
use cranelift_codegen::isa;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
/// Return an `isa` builder configured for the current host
|
||||
/// machine, or `Err(())` if the host machine is not supported
|
||||
/// in the current configuration.
|
||||
pub fn builder() -> Result<isa::Builder, &'static str> {
|
||||
builder_with_options(true)
|
||||
}
|
||||
|
||||
/// Return an `isa` builder configured for the current host
|
||||
/// machine, or `Err(())` if the host machine is not supported
|
||||
/// in the current configuration.
|
||||
///
|
||||
/// Selects the given backend variant specifically; this is
|
||||
/// useful when more than oen backend exists for a given target
|
||||
/// (e.g., on x86-64).
|
||||
pub fn builder_with_options(infer_native_flags: bool) -> Result<isa::Builder, &'static str> {
|
||||
let mut isa_builder = isa::lookup(Triple::host()).map_err(|err| match err {
|
||||
isa::LookupError::SupportDisabled => "support for architecture disabled at compile time",
|
||||
isa::LookupError::Unsupported => "unsupported architecture",
|
||||
})?;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
use cranelift_codegen::settings::Configurable;
|
||||
|
||||
if !std::is_x86_feature_detected!("sse2") {
|
||||
return Err("x86 support requires SSE2");
|
||||
}
|
||||
|
||||
if !infer_native_flags {
|
||||
return Ok(isa_builder);
|
||||
}
|
||||
|
||||
// These are temporarily enabled by default (see #3810 for
|
||||
// more) so that a default-constructed `Flags` can work with
|
||||
// default Wasmtime features. Otherwise, the user must
|
||||
// explicitly use native flags or turn these on when on x86-64
|
||||
// platforms to avoid a configuration panic. In order for the
|
||||
// "enable if detected" logic below to work, we must turn them
|
||||
// *off* (differing from the default) and then re-enable below
|
||||
// if present.
|
||||
isa_builder.set("has_sse3", "false").unwrap();
|
||||
isa_builder.set("has_ssse3", "false").unwrap();
|
||||
isa_builder.set("has_sse41", "false").unwrap();
|
||||
isa_builder.set("has_sse42", "false").unwrap();
|
||||
|
||||
if std::is_x86_feature_detected!("sse3") {
|
||||
isa_builder.enable("has_sse3").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("ssse3") {
|
||||
isa_builder.enable("has_ssse3").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("sse4.1") {
|
||||
isa_builder.enable("has_sse41").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("sse4.2") {
|
||||
isa_builder.enable("has_sse42").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("popcnt") {
|
||||
isa_builder.enable("has_popcnt").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("avx") {
|
||||
isa_builder.enable("has_avx").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("avx2") {
|
||||
isa_builder.enable("has_avx2").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("fma") {
|
||||
isa_builder.enable("has_fma").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("bmi1") {
|
||||
isa_builder.enable("has_bmi1").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("bmi2") {
|
||||
isa_builder.enable("has_bmi2").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("avx512bitalg") {
|
||||
isa_builder.enable("has_avx512bitalg").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("avx512dq") {
|
||||
isa_builder.enable("has_avx512dq").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("avx512f") {
|
||||
isa_builder.enable("has_avx512f").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("avx512vl") {
|
||||
isa_builder.enable("has_avx512vl").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("avx512vbmi") {
|
||||
isa_builder.enable("has_avx512vbmi").unwrap();
|
||||
}
|
||||
if std::is_x86_feature_detected!("lzcnt") {
|
||||
isa_builder.enable("has_lzcnt").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
{
|
||||
use cranelift_codegen::settings::Configurable;
|
||||
|
||||
if !infer_native_flags {
|
||||
return Ok(isa_builder);
|
||||
}
|
||||
|
||||
if std::arch::is_aarch64_feature_detected!("lse") {
|
||||
isa_builder.enable("has_lse").unwrap();
|
||||
}
|
||||
|
||||
if std::arch::is_aarch64_feature_detected!("paca") {
|
||||
isa_builder.enable("has_pauth").unwrap();
|
||||
}
|
||||
|
||||
if cfg!(target_os = "macos") {
|
||||
// Pointer authentication is always available on Apple Silicon.
|
||||
isa_builder.enable("sign_return_address").unwrap();
|
||||
// macOS enforces the use of the B key for return addresses.
|
||||
isa_builder.enable("sign_return_address_with_bkey").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// There is no is_s390x_feature_detected macro yet, so for now
|
||||
// we use getauxval from the libc crate directly.
|
||||
#[cfg(all(target_arch = "s390x", target_os = "linux"))]
|
||||
{
|
||||
use cranelift_codegen::settings::Configurable;
|
||||
|
||||
if !infer_native_flags {
|
||||
return Ok(isa_builder);
|
||||
}
|
||||
|
||||
let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
|
||||
const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768;
|
||||
if (v & HWCAP_S390X_VXRS_EXT2) != 0 {
|
||||
isa_builder.enable("has_vxrs_ext2").unwrap();
|
||||
// There is no separate HWCAP bit for mie2, so assume
|
||||
// that any machine with vxrs_ext2 also has mie2.
|
||||
isa_builder.enable("has_mie2").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// `is_riscv_feature_detected` is nightly only for now, use
|
||||
// getauxval from the libc crate directly as a temporary measure.
|
||||
#[cfg(all(target_arch = "riscv64", target_os = "linux"))]
|
||||
{
|
||||
use cranelift_codegen::settings::Configurable;
|
||||
|
||||
if !infer_native_flags {
|
||||
return Ok(isa_builder);
|
||||
}
|
||||
|
||||
let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
|
||||
|
||||
const HWCAP_RISCV_EXT_A: libc::c_ulong = 1 << (b'a' - b'a');
|
||||
const HWCAP_RISCV_EXT_C: libc::c_ulong = 1 << (b'c' - b'a');
|
||||
const HWCAP_RISCV_EXT_D: libc::c_ulong = 1 << (b'd' - b'a');
|
||||
const HWCAP_RISCV_EXT_F: libc::c_ulong = 1 << (b'f' - b'a');
|
||||
const HWCAP_RISCV_EXT_M: libc::c_ulong = 1 << (b'm' - b'a');
|
||||
const HWCAP_RISCV_EXT_V: libc::c_ulong = 1 << (b'v' - b'a');
|
||||
|
||||
if (v & HWCAP_RISCV_EXT_A) != 0 {
|
||||
isa_builder.enable("has_a").unwrap();
|
||||
}
|
||||
|
||||
if (v & HWCAP_RISCV_EXT_C) != 0 {
|
||||
isa_builder.enable("has_c").unwrap();
|
||||
}
|
||||
|
||||
if (v & HWCAP_RISCV_EXT_D) != 0 {
|
||||
isa_builder.enable("has_d").unwrap();
|
||||
}
|
||||
|
||||
if (v & HWCAP_RISCV_EXT_F) != 0 {
|
||||
isa_builder.enable("has_f").unwrap();
|
||||
|
||||
// TODO: There doesn't seem to be a bit associated with this extension
|
||||
// rust enables it with the `f` extension:
|
||||
// https://github.com/rust-lang/stdarch/blob/790411f93c4b5eada3c23abb4c9a063fb0b24d99/crates/std_detect/src/detect/os/linux/riscv.rs#L43
|
||||
isa_builder.enable("has_zicsr").unwrap();
|
||||
}
|
||||
|
||||
if (v & HWCAP_RISCV_EXT_M) != 0 {
|
||||
isa_builder.enable("has_m").unwrap();
|
||||
}
|
||||
|
||||
if (v & HWCAP_RISCV_EXT_V) != 0 {
|
||||
isa_builder.enable("has_v").unwrap();
|
||||
}
|
||||
|
||||
// TODO: ZiFencei does not have a bit associated with it
|
||||
// TODO: Zbkb does not have a bit associated with it
|
||||
}
|
||||
|
||||
// squelch warnings about unused mut/variables on some platforms.
|
||||
drop(&mut isa_builder);
|
||||
drop(infer_native_flags);
|
||||
|
||||
Ok(isa_builder)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::builder;
|
||||
use cranelift_codegen::isa::CallConv;
|
||||
use cranelift_codegen::settings;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
if let Ok(isa_builder) = builder() {
|
||||
let flag_builder = settings::builder();
|
||||
let isa = isa_builder.finish(settings::Flags::new(flag_builder)).unwrap();
|
||||
|
||||
if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
|
||||
assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64);
|
||||
} else if cfg!(any(unix, target_os = "nebulet")) {
|
||||
assert_eq!(isa.default_call_conv(), CallConv::SystemV);
|
||||
} else if cfg!(windows) {
|
||||
assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall);
|
||||
}
|
||||
|
||||
if cfg!(target_pointer_width = "64") {
|
||||
assert_eq!(isa.pointer_bits(), 64);
|
||||
} else if cfg!(target_pointer_width = "32") {
|
||||
assert_eq!(isa.pointer_bits(), 32);
|
||||
} else if cfg!(target_pointer_width = "16") {
|
||||
assert_eq!(isa.pointer_bits(), 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Version number of this crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
|
@ -20,6 +20,14 @@ use indexmap::IndexSet;
|
|||
pub(crate) use emit::{DebugReloc, DebugRelocName};
|
||||
pub(crate) use unwind::UnwindContext;
|
||||
|
||||
pub(crate) fn producer() -> String {
|
||||
format!(
|
||||
"cg_clif (rustc {}, cranelift {})",
|
||||
rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
|
||||
cranelift_codegen::VERSION,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) struct DebugContext {
|
||||
endian: RunTimeEndian,
|
||||
|
||||
|
|
@ -57,11 +65,7 @@ impl DebugContext {
|
|||
|
||||
let mut dwarf = DwarfUnit::new(encoding);
|
||||
|
||||
let producer = format!(
|
||||
"cg_clif (rustc {}, cranelift {})",
|
||||
rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
|
||||
cranelift_codegen::VERSION,
|
||||
);
|
||||
let producer = producer();
|
||||
let comp_dir = tcx
|
||||
.sess
|
||||
.opts
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ impl OngoingCodegen {
|
|||
|
||||
self.concurrency_limiter.finished();
|
||||
|
||||
sess.abort_if_errors();
|
||||
|
||||
(
|
||||
CodegenResults {
|
||||
modules,
|
||||
|
|
@ -169,10 +171,22 @@ fn emit_cgu(
|
|||
fn emit_module(
|
||||
output_filenames: &OutputFilenames,
|
||||
prof: &SelfProfilerRef,
|
||||
object: cranelift_object::object::write::Object<'_>,
|
||||
mut object: cranelift_object::object::write::Object<'_>,
|
||||
kind: ModuleKind,
|
||||
name: String,
|
||||
) -> Result<CompiledModule, String> {
|
||||
if object.format() == cranelift_object::object::BinaryFormat::Elf {
|
||||
let comment_section = object.add_section(
|
||||
Vec::new(),
|
||||
b".comment".to_vec(),
|
||||
cranelift_object::object::SectionKind::OtherString,
|
||||
);
|
||||
let mut producer = vec![0];
|
||||
producer.extend(crate::debuginfo::producer().as_bytes());
|
||||
producer.push(0);
|
||||
object.set_section_data(comment_section, producer, 1);
|
||||
}
|
||||
|
||||
let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name));
|
||||
let mut file = match File::create(&tmp_file) {
|
||||
Ok(file) => file,
|
||||
|
|
@ -399,8 +413,6 @@ pub(crate) fn run_aot(
|
|||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
tcx.sess.abort_if_errors();
|
||||
|
||||
let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
|
||||
let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true);
|
||||
let created_alloc_shim =
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
|
||||
// cast float to int
|
||||
let a_lane = match lane_ty {
|
||||
types::F32 => fx.bcx.ins().bitcast(types::I32, a_lane),
|
||||
types::F64 => fx.bcx.ins().bitcast(types::I64, a_lane),
|
||||
types::F32 => codegen_bitcast(fx, types::I32, a_lane),
|
||||
types::F64 => codegen_bitcast(fx, types::I64, a_lane),
|
||||
_ => a_lane,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ mod simd;
|
|||
pub(crate) use cpuid::codegen_cpuid_call;
|
||||
pub(crate) use llvm::codegen_llvm_intrinsic_call;
|
||||
|
||||
use rustc_middle::ty::layout::HasParamEnv;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
|
|
@ -200,7 +201,7 @@ fn bool_to_zero_or_max_uint<'tcx>(
|
|||
let mut res = fx.bcx.ins().bmask(int_ty, val);
|
||||
|
||||
if ty.is_float() {
|
||||
res = fx.bcx.ins().bitcast(ty, res);
|
||||
res = codegen_bitcast(fx, ty, res);
|
||||
}
|
||||
|
||||
res
|
||||
|
|
@ -240,10 +241,9 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
|
|||
substs,
|
||||
args,
|
||||
destination,
|
||||
target,
|
||||
source_info.span,
|
||||
);
|
||||
let ret_block = fx.get_block(target);
|
||||
fx.bcx.ins().jump(ret_block, &[]);
|
||||
} else if codegen_float_intrinsic_call(fx, intrinsic, args, destination) {
|
||||
let ret_block = fx.get_block(target);
|
||||
fx.bcx.ins().jump(ret_block, &[]);
|
||||
|
|
@ -650,7 +650,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
let layout = fx.layout_of(substs.type_at(0));
|
||||
if layout.abi.is_uninhabited() {
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic(
|
||||
crate::base::codegen_panic_nounwind(
|
||||
fx,
|
||||
&format!("attempted to instantiate uninhabited type `{}`", layout.ty),
|
||||
source_info,
|
||||
|
|
@ -659,9 +659,11 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
if intrinsic == sym::assert_zero_valid && !fx.tcx.permits_zero_init(layout) {
|
||||
if intrinsic == sym::assert_zero_valid
|
||||
&& !fx.tcx.permits_zero_init(fx.param_env().and(layout))
|
||||
{
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic(
|
||||
crate::base::codegen_panic_nounwind(
|
||||
fx,
|
||||
&format!(
|
||||
"attempted to zero-initialize type `{}`, which is invalid",
|
||||
|
|
@ -674,10 +676,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
}
|
||||
|
||||
if intrinsic == sym::assert_mem_uninitialized_valid
|
||||
&& !fx.tcx.permits_uninit_init(layout)
|
||||
&& !fx.tcx.permits_uninit_init(fx.param_env().and(layout))
|
||||
{
|
||||
with_no_trimmed_paths!({
|
||||
crate::base::codegen_panic(
|
||||
crate::base::codegen_panic_nounwind(
|
||||
fx,
|
||||
&format!(
|
||||
"attempted to leave type `{}` uninitialized, which is invalid",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
_substs: SubstsRef<'tcx>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
ret: CPlace<'tcx>,
|
||||
target: BasicBlock,
|
||||
span: Span,
|
||||
) {
|
||||
match intrinsic {
|
||||
|
|
@ -277,16 +278,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
} else {
|
||||
fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant");
|
||||
let trap_block = fx.bcx.create_block();
|
||||
let dummy_block = fx.bcx.create_block();
|
||||
let true_ = fx.bcx.ins().iconst(types::I8, 1);
|
||||
fx.bcx.ins().brnz(true_, trap_block, &[]);
|
||||
fx.bcx.ins().jump(dummy_block, &[]);
|
||||
let ret_block = fx.get_block(target);
|
||||
fx.bcx.ins().jump(ret_block, &[]);
|
||||
fx.bcx.switch_to_block(trap_block);
|
||||
crate::trap::trap_unimplemented(
|
||||
fx,
|
||||
"Index argument for `simd_extract` is not a constant",
|
||||
);
|
||||
fx.bcx.switch_to_block(dummy_block);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -770,11 +770,119 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
});
|
||||
}
|
||||
|
||||
// simd_arith_offset
|
||||
// simd_scatter
|
||||
// simd_gather
|
||||
sym::simd_expose_addr | sym::simd_from_exposed_addr | sym::simd_cast_ptr => {
|
||||
intrinsic_args!(fx, args => (arg); intrinsic);
|
||||
ret.write_cvalue_transmute(fx, arg);
|
||||
}
|
||||
|
||||
sym::simd_arith_offset => {
|
||||
intrinsic_args!(fx, args => (ptr, offset); intrinsic);
|
||||
|
||||
let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap().ty;
|
||||
let pointee_size = fx.layout_of(pointee_ty).size.bytes();
|
||||
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let ret_lane_layout = fx.layout_of(ret_lane_ty);
|
||||
assert_eq!(lane_count, ret_lane_count);
|
||||
|
||||
for lane_idx in 0..lane_count {
|
||||
let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
let offset_lane = offset.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
|
||||
let ptr_diff = if pointee_size != 1 {
|
||||
fx.bcx.ins().imul_imm(offset_lane, pointee_size as i64)
|
||||
} else {
|
||||
offset_lane
|
||||
};
|
||||
let res_lane = fx.bcx.ins().iadd(ptr_lane, ptr_diff);
|
||||
let res_lane = CValue::by_val(res_lane, ret_lane_layout);
|
||||
|
||||
ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
|
||||
}
|
||||
}
|
||||
|
||||
sym::simd_gather => {
|
||||
intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
|
||||
|
||||
let (val_lane_count, val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
|
||||
assert_eq!(val_lane_count, ptr_lane_count);
|
||||
assert_eq!(val_lane_count, mask_lane_count);
|
||||
assert_eq!(val_lane_count, ret_lane_count);
|
||||
|
||||
let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap();
|
||||
let ret_lane_layout = fx.layout_of(ret_lane_ty);
|
||||
|
||||
for lane_idx in 0..ptr_lane_count {
|
||||
let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
|
||||
let if_enabled = fx.bcx.create_block();
|
||||
let if_disabled = fx.bcx.create_block();
|
||||
let next = fx.bcx.create_block();
|
||||
let res_lane = fx.bcx.append_block_param(next, lane_clif_ty);
|
||||
|
||||
fx.bcx.ins().brnz(mask_lane, if_enabled, &[]);
|
||||
fx.bcx.ins().jump(if_disabled, &[]);
|
||||
fx.bcx.seal_block(if_enabled);
|
||||
fx.bcx.seal_block(if_disabled);
|
||||
|
||||
fx.bcx.switch_to_block(if_enabled);
|
||||
let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), ptr_lane, 0);
|
||||
fx.bcx.ins().jump(next, &[res]);
|
||||
|
||||
fx.bcx.switch_to_block(if_disabled);
|
||||
fx.bcx.ins().jump(next, &[val_lane]);
|
||||
|
||||
fx.bcx.seal_block(next);
|
||||
fx.bcx.switch_to_block(next);
|
||||
|
||||
fx.bcx.ins().nop();
|
||||
|
||||
ret.place_lane(fx, lane_idx)
|
||||
.write_cvalue(fx, CValue::by_val(res_lane, ret_lane_layout));
|
||||
}
|
||||
}
|
||||
|
||||
sym::simd_scatter => {
|
||||
intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
|
||||
|
||||
let (val_lane_count, _val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
|
||||
let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
|
||||
assert_eq!(val_lane_count, ptr_lane_count);
|
||||
assert_eq!(val_lane_count, mask_lane_count);
|
||||
|
||||
for lane_idx in 0..ptr_lane_count {
|
||||
let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
|
||||
|
||||
let if_enabled = fx.bcx.create_block();
|
||||
let next = fx.bcx.create_block();
|
||||
|
||||
fx.bcx.ins().brnz(mask_lane, if_enabled, &[]);
|
||||
fx.bcx.ins().jump(next, &[]);
|
||||
fx.bcx.seal_block(if_enabled);
|
||||
|
||||
fx.bcx.switch_to_block(if_enabled);
|
||||
fx.bcx.ins().store(MemFlags::trusted(), val_lane, ptr_lane, 0);
|
||||
fx.bcx.ins().jump(next, &[]);
|
||||
|
||||
fx.bcx.seal_block(next);
|
||||
fx.bcx.switch_to_block(next);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
|
||||
fx.tcx.sess.span_err(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
|
||||
// Prevent verifier error
|
||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
||||
}
|
||||
}
|
||||
let ret_block = fx.get_block(target);
|
||||
fx.bcx.ins().jump(ret_block, &[]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ mod compiler_builtins;
|
|||
mod concurrency_limiter;
|
||||
mod config;
|
||||
mod constant;
|
||||
// FIXME revert back to the external crate with Cranelift 0.93
|
||||
mod cranelift_native;
|
||||
mod debuginfo;
|
||||
mod discriminant;
|
||||
mod driver;
|
||||
|
|
@ -278,12 +280,14 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
|
|||
}
|
||||
}
|
||||
|
||||
if target_triple.architecture == target_lexicon::Architecture::X86_64 {
|
||||
if let target_lexicon::Architecture::Aarch64(_) | target_lexicon::Architecture::X86_64 =
|
||||
target_triple.architecture
|
||||
{
|
||||
// Windows depends on stack probes to grow the committed part of the stack
|
||||
flags_builder.enable("enable_probestack").unwrap();
|
||||
flags_builder.set("probestack_strategy", "inline").unwrap();
|
||||
} else {
|
||||
// __cranelift_probestack is not provided and inline stack probes are only supported on x86_64
|
||||
// __cranelift_probestack is not provided and inline stack probes are only supported on AArch64 and x86_64
|
||||
flags_builder.set("enable_probestack", "false").unwrap();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
is_main_fn: bool,
|
||||
sigpipe: u8,
|
||||
) {
|
||||
let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
|
||||
let main_ret_ty = tcx.fn_sig(rust_main_def_id).no_bound_vars().unwrap().output();
|
||||
// Given that `main()` has no arguments,
|
||||
// then its return type cannot have
|
||||
// late-bound regions, since late-bound
|
||||
|
|
@ -64,13 +64,20 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
],
|
||||
returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
|
||||
call_conv: crate::conv_to_call_conv(
|
||||
tcx.sess,
|
||||
tcx.sess.target.options.entry_abi,
|
||||
m.target_config().default_call_conv,
|
||||
),
|
||||
};
|
||||
|
||||
let entry_name = tcx.sess.target.options.entry_name.as_ref();
|
||||
let cmain_func_id = m.declare_function(entry_name, Linkage::Export, &cmain_sig).unwrap();
|
||||
let cmain_func_id = match m.declare_function(entry_name, Linkage::Export, &cmain_sig) {
|
||||
Ok(func_id) => func_id,
|
||||
Err(err) => {
|
||||
tcx.sess
|
||||
.fatal(&format!("entry symbol `{entry_name}` declared multiple times: {err}"));
|
||||
}
|
||||
};
|
||||
|
||||
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
|
||||
|
||||
|
|
@ -162,7 +169,11 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
bcx.seal_all_blocks();
|
||||
bcx.finalize();
|
||||
}
|
||||
m.define_function(cmain_func_id, &mut ctx).unwrap();
|
||||
|
||||
if let Err(err) = m.define_function(cmain_func_id, &mut ctx) {
|
||||
tcx.sess.fatal(&format!("entry symbol `{entry_name}` defined multiple times: {err}"));
|
||||
}
|
||||
|
||||
unwind_context.add_function(cmain_func_id, &ctx, m.isa());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use cranelift_frontend::FunctionBuilder;
|
|||
/// otherwise return the given value and false.
|
||||
pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) {
|
||||
if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
|
||||
match bcx.func.dfg[arg_inst] {
|
||||
match bcx.func.dfg.insts[arg_inst] {
|
||||
// This is the lowering of `Rvalue::Not`
|
||||
InstructionData::IntCompareImm {
|
||||
opcode: Opcode::IcmpImm,
|
||||
|
|
@ -34,7 +34,7 @@ pub(crate) fn maybe_known_branch_taken(
|
|||
return None;
|
||||
};
|
||||
|
||||
match bcx.func.dfg[arg_inst] {
|
||||
match bcx.func.dfg.insts[arg_inst] {
|
||||
InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
|
||||
if test_zero {
|
||||
Some(imm.bits() == 0)
|
||||
|
|
|
|||
|
|
@ -514,8 +514,8 @@ impl<'tcx> CPlace<'tcx> {
|
|||
(types::I32, types::F32)
|
||||
| (types::F32, types::I32)
|
||||
| (types::I64, types::F64)
|
||||
| (types::F64, types::I64) => fx.bcx.ins().bitcast(dst_ty, data),
|
||||
_ if src_ty.is_vector() && dst_ty.is_vector() => fx.bcx.ins().bitcast(dst_ty, data),
|
||||
| (types::F64, types::I64) => codegen_bitcast(fx, dst_ty, data),
|
||||
_ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data),
|
||||
_ if src_ty.is_vector() || dst_ty.is_vector() => {
|
||||
// FIXME do something more efficient for transmutes between vectors and integers.
|
||||
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
# This block is ignored by rustc
|
||||
set -e
|
||||
echo "[BUILD] y.rs" 1>&2
|
||||
rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021
|
||||
rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021 -Cpanic=abort
|
||||
exec ${0/.rs/.bin} $@
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -709,7 +709,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
bx.range_metadata(load, vr);
|
||||
}
|
||||
}
|
||||
abi::Pointer if vr.start < vr.end && !vr.contains(0) => {
|
||||
abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => {
|
||||
bx.nonnull_metadata(load);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
let base_addr = self.const_bitcast(base_addr, self.usize_type);
|
||||
let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
|
||||
let ptr = self.const_bitcast(base_addr + offset, ptr_type);
|
||||
if layout.primitive() != Pointer {
|
||||
if !matches!(layout.primitive(), Pointer(_)) {
|
||||
self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -322,13 +322,16 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
|
|||
)
|
||||
.expect("const_alloc_to_llvm: could not read relocation pointer")
|
||||
as u64;
|
||||
|
||||
let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
|
||||
|
||||
llvals.push(cx.scalar_to_backend(
|
||||
InterpScalar::from_pointer(
|
||||
interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
|
||||
&cx.tcx,
|
||||
),
|
||||
abi::Scalar::Initialized { value: Primitive::Pointer, valid_range: WrappingRange::full(dl.pointer_size) },
|
||||
cx.type_i8p(),
|
||||
abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) },
|
||||
cx.type_i8p_ext(address_space),
|
||||
));
|
||||
next_offset = offset + pointer_size;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
Int(i, false) => cx.type_from_unsigned_integer(i),
|
||||
F32 => cx.type_f32(),
|
||||
F64 => cx.type_f64(),
|
||||
Pointer => {
|
||||
Pointer(address_space) => {
|
||||
// If we know the alignment, pick something better than i8.
|
||||
let pointee =
|
||||
if let Some(pointee) = self.pointee_info_at(cx, offset) {
|
||||
|
|
@ -262,7 +262,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
else {
|
||||
cx.type_i8()
|
||||
};
|
||||
cx.type_ptr_to(pointee)
|
||||
cx.type_ptr_to_ext(pointee, address_space)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -849,6 +849,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
|
|||
/// Helper function to get the LLVM type for a Scalar. Pointers are returned as
|
||||
/// the equivalent integer type.
|
||||
fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type {
|
||||
let dl = &cx.tcx.data_layout;
|
||||
match scalar.primitive() {
|
||||
Primitive::Int(Integer::I8, _) => cx.type_i8(),
|
||||
Primitive::Int(Integer::I16, _) => cx.type_i16(),
|
||||
|
|
@ -856,7 +857,8 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty
|
|||
Primitive::Int(Integer::I64, _) => cx.type_i64(),
|
||||
Primitive::F32 => cx.type_f32(),
|
||||
Primitive::F64 => cx.type_f64(),
|
||||
Primitive::Pointer => cx.type_isize(),
|
||||
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
|
||||
Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
@ -868,6 +870,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
|
|||
reg: InlineAsmRegClass,
|
||||
layout: &TyAndLayout<'tcx>,
|
||||
) -> &'ll Value {
|
||||
let dl = &bx.tcx.data_layout;
|
||||
match (reg, layout.abi) {
|
||||
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
|
||||
if let Primitive::Int(Integer::I8, _) = s.primitive() {
|
||||
|
|
@ -881,8 +884,10 @@ fn llvm_fixup_input<'ll, 'tcx>(
|
|||
let elem_ty = llvm_asm_scalar_type(bx.cx, s);
|
||||
let count = 16 / layout.size.bytes();
|
||||
let vec_ty = bx.cx.type_vector(elem_ty, count);
|
||||
if let Primitive::Pointer = s.primitive() {
|
||||
value = bx.ptrtoint(value, bx.cx.type_isize());
|
||||
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
|
||||
if let Primitive::Pointer(_) = s.primitive() {
|
||||
let t = bx.type_from_integer(dl.ptr_sized_integer());
|
||||
value = bx.ptrtoint(value, t);
|
||||
}
|
||||
bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0))
|
||||
}
|
||||
|
|
@ -958,7 +963,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
|
|||
}
|
||||
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) => {
|
||||
value = bx.extract_element(value, bx.const_i32(0));
|
||||
if let Primitive::Pointer = s.primitive() {
|
||||
if let Primitive::Pointer(_) = s.primitive() {
|
||||
value = bx.inttoptr(value, layout.llvm_type(bx.cx));
|
||||
}
|
||||
value
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
|
|||
// the WebAssembly specification, which has this feature. This won't be
|
||||
// needed when LLVM enables this `multivalue` feature by default.
|
||||
if !cx.tcx.is_closure(instance.def_id()) {
|
||||
let abi = cx.tcx.fn_sig(instance.def_id()).abi();
|
||||
let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi();
|
||||
if abi == Abi::Wasm {
|
||||
function_features.push("+multivalue".to_string());
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue