Unloaded,
}
-#[derive(Copy, Clone, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)]
pub struct ModSpans {
/// `inner_span` covers the body of the module; for a file module, its the whole file.
/// For an inline module, its the span inside the `{ ... }`, not including the curly braces.
pub inject_use_span: Span,
}
-impl Default for ModSpans {
- fn default() -> ModSpans {
- ModSpans { inner_span: Default::default(), inject_use_span: Default::default() }
- }
-}
-
/// Foreign module declaration.
///
/// E.g., `extern { .. }` or `extern "C" { .. }`.
.map_bound(|p| p.predicates),
None,
),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*def_id), Some(*substs))
}
ty::Closure(_, substs) => match substs.as_closure().kind() {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *output_ty.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() {
output_ty = self.infcx.tcx.type_of(def_id)
};
// Otherwise, we need to find the minimum remaining choice, if
// any, and take that.
debug!("choice_regions remaining are {:#?}", choice_regions);
- let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
- let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
- let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
- match (r1_outlives_r2, r2_outlives_r1) {
- (true, true) => Some(r1.min(r2)),
- (true, false) => Some(r2),
- (false, true) => Some(r1),
- (false, false) => None,
- }
+ let Some(&min_choice) = choice_regions.iter().find(|&r1| {
+ choice_regions.iter().all(|&r2| {
+ self.universal_region_relations.outlives(r2, *r1)
+ })
+ }) else {
+ debug!("no choice region outlived by all others");
+ return false;
};
- let mut min_choice = choice_regions[0];
- for &other_option in &choice_regions[1..] {
- debug!(?min_choice, ?other_option,);
- match min(min_choice, other_option) {
- Some(m) => min_choice = m,
- None => {
- debug!(?min_choice, ?other_option, "incomparable; no min choice",);
- return false;
- }
- }
- }
let min_choice_scc = self.constraint_sccs.scc(min_choice);
debug!(?min_choice, ?min_choice_scc);
folder: target
prepare_script:
- . $HOME/.cargo/env
- - git config --global user.email "user@example.com"
- - git config --global user.name "User"
- ./y.rs prepare
test_script:
- . $HOME/.cargo/env
- name: Rustfmt
run: |
cargo fmt --check
+ rustfmt --check build_system/mod.rs
build:
runs-on: ${{ matrix.os }}
fail-fast: false
matrix:
include:
- - os: ubuntu-latest
+ - os: ubuntu-20.04 # FIXME switch to ubuntu-22.04 once #1303 is fixed
env:
TARGET_TRIPLE: x86_64-unknown-linux-gnu
- os: macos-latest
- os: ubuntu-latest
env:
TARGET_TRIPLE: aarch64-unknown-linux-gnu
+ # s390x requires QEMU 6.1 or greater, we could build it from source, but ubuntu 22.04 comes with 6.2 by default
+ - os: ubuntu-latest
+ env:
+ TARGET_TRIPLE: s390x-unknown-linux-gnu
steps:
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-cargo-installed-crates
- name: Cache cargo registry and index
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
- path: target
+ path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Install MinGW toolchain and wine
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user
- - name: Prepare dependencies
+ - name: Install s390x toolchain and qemu
+ if: matrix.env.TARGET_TRIPLE == 's390x-unknown-linux-gnu'
run: |
- git config --global user.email "user@example.com"
- git config --global user.name "User"
- ./y.rs prepare
+ sudo apt-get update
+ sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
+
+ - name: Prepare dependencies
+ run: ./y.rs prepare
- name: Build without unstable features
env:
./y.rs test
- name: Package prebuilt cg_clif
- run: tar cvfJ cg_clif.tar.xz build
+ run: tar cvfJ cg_clif.tar.xz dist
- name: Upload prebuilt cg_clif
if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
- name: Upload prebuilt cg_clif (cross compile)
if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
path: cg_clif.tar.xz
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ 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@v2
+ uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
- path: target
+ path: build/cg_clif
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Set MinGW as the default toolchain
- name: Prepare dependencies
run: |
- git config --global user.email "user@example.com"
- git config --global user.name "User"
git config --global core.autocrlf false
rustc y.rs -o y.exe -g
./y.exe prepare
# 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
+
+ # 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 build
+ run: tar cvf cg_clif.tar dist
- name: Upload prebuilt cg_clif
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
path: cg_clif.tar
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ubuntu-latest-cargo-installed-crates
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-cargo-installed-crates
- name: Cache cargo registry and index
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
- path: target
+ path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Prepare dependencies
- uses: actions/checkout@v3
- name: Cache cargo installed crates
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-cargo-installed-crates
- name: Cache cargo registry and index
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo target dir
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
- path: target
+ path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- name: Prepare dependencies
/build_sysroot/sysroot_src
/build_sysroot/compiler-builtins
/build_sysroot/rustc_version
+/dist
/rust
/download
"rust-analyzer.imports.granularity.enforce": true,
"rust-analyzer.imports.granularity.group": "module",
"rust-analyzer.imports.prefix": "crate",
- "rust-analyzer.cargo.features": ["unstable-features"],
+ "rust-analyzer.cargo.features": ["unstable-features", "__check_build_system_using_ra"],
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
- //"./build_sysroot/sysroot_src/library/std/Cargo.toml",
{
- "roots": [
- "./example/mini_core.rs",
- "./example/mini_core_hello_world.rs",
- "./example/mod_bench.rs"
- ],
"crates": [
{
"root_module": "./example/mini_core.rs",
]
},
{
- "roots": ["./example/std_example.rs"],
+ "sysroot_src": "./build_sysroot/sysroot_src/library",
"crates": [
{
"root_module": "./example/std_example.rs",
- "edition": "2018",
- "deps": [{ "crate": 1, "name": "std" }],
- "cfg": [],
- },
- {
- "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
- "edition": "2018",
- "deps": [],
- "cfg": [],
- },
- ]
- },
- {
- "roots": ["./y.rs"],
- "crates": [
- {
- "root_module": "./y.rs",
- "edition": "2018",
- "deps": [{ "crate": 1, "name": "std" }],
- "cfg": [],
- },
- {
- "root_module": "./build_sysroot/sysroot_src/library/std/src/lib.rs",
- "edition": "2018",
+ "edition": "2015",
"deps": [],
"cfg": [],
},
[[package]]
name = "anyhow"
-version = "1.0.60"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
+checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
[[package]]
name = "arrayvec"
[[package]]
name = "bumpalo"
-version = "3.11.0"
+version = "3.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
name = "byteorder"
[[package]]
name = "cranelift-bforest"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44409ccf2d0f663920cab563d2b79fcd6b2e9a2bcc6e929fef76c8f82ad6c17a"
+checksum = "b62c772976416112fa4484cbd688cb6fb35fd430005c1c586224fc014018abad"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98de2018ad96eb97f621f7d6b900a0cc661aec8d02ea4a50e56ecb48e5a2fcaf"
+checksum = "9b40ed2dd13c2ac7e24f88a3090c68ad3414eb1d066a95f8f1f7b3b819cb4e46"
dependencies = [
"arrayvec",
"bumpalo",
"cranelift-bforest",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
+ "cranelift-egraph",
"cranelift-entity",
"cranelift-isle",
"gimli",
[[package]]
name = "cranelift-codegen-meta"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5287ce36e6c4758fbaf298bd1a8697ad97a4f2375a3d1b61142ea538db4877e5"
+checksum = "bb927a8f1c27c34ee3759b6b0ffa528d2330405d5cc4511f0cab33fe2279f4b5"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2855c24219e2f08827f3f4ffb2da92e134ae8d8ecc185b11ec8f9878cf5f588e"
+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",
+]
[[package]]
name = "cranelift-entity"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b65673279d75d34bf11af9660ae2dbd1c22e6d28f163f5c72f4e1dc56d56103"
+checksum = "0637ffde963cb5d759bc4d454cfa364b6509e6c74cdaa21298add0ed9276f346"
[[package]]
name = "cranelift-frontend"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed2b3d7a4751163f6c4a349205ab1b7d9c00eecf19dcea48592ef1f7688eefc"
+checksum = "fb72b8342685e850cb037350418f62cc4fc55d6c2eb9c7ca01b82f9f1a6f3d56"
dependencies = [
"cranelift-codegen",
"log",
[[package]]
name = "cranelift-isle"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be64cecea9d90105fc6a2ba2d003e98c867c1d6c4c86cc878f97ad9fb916293"
+checksum = "850579cb9e4b448f7c301f1e6e6cbad99abe3f1f1d878a4994cb66e33c6db8cd"
[[package]]
name = "cranelift-jit"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98ed42a70a0c9c388e34ec9477f57fc7300f541b1e5136a0e2ea02b1fac6015"
+checksum = "9add822ad66dcbe152b5ab57de10240a2df4505099f2f6c27159acb711890bd4"
dependencies = [
"anyhow",
"cranelift-codegen",
"log",
"region",
"target-lexicon",
+ "wasmtime-jit-icache-coherence",
"windows-sys",
]
[[package]]
name = "cranelift-module"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d658ac7f156708bfccb647216cc8b9387469f50d352ba4ad80150541e4ae2d49"
+checksum = "406b772626fc2664864cf947f3895a23b619895c7fff635f3622e2d857f4492f"
dependencies = [
"anyhow",
"cranelift-codegen",
[[package]]
name = "cranelift-native"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a03a6ac1b063e416ca4b93f6247978c991475e8271465340caa6f92f3c16a4"
+checksum = "2d0a279e5bcba3e0466c734d8d8eb6bfc1ad29e95c37f3e4955b492b5616335e"
dependencies = [
"cranelift-codegen",
"libc",
[[package]]
name = "cranelift-object"
-version = "0.88.1"
+version = "0.90.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eef0b4119b645b870a43a036d76c0ada3a076b1f82e8b8487659304c8b09049b"
+checksum = "39793c550f0c1d7db96c2fc1324583670c8143befe6edbfbaf1c68aba53be983"
dependencies = [
"anyhow",
"cranelift-codegen",
"cfg-if",
]
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
[[package]]
name = "fxhash"
version = "0.2.1"
[[package]]
name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
+ "fallible-iterator",
"indexmap",
+ "stable_deref_trait",
]
[[package]]
[[package]]
name = "indexmap"
-version = "1.9.1"
+version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
[[package]]
name = "libc"
-version = "0.2.127"
+version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "505e71a4706fa491e9b1b55f51b95d4037d0821ee40131190475f692b35b009b"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "libloading"
-version = "0.7.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
[[package]]
name = "once_cell"
-version = "1.13.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "regalloc2"
-version = "0.3.2"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779"
+checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5"
dependencies = [
"fxhash",
"log",
[[package]]
name = "smallvec"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "target-lexicon"
-version = "0.12.4"
+version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1"
+checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d"
[[package]]
name = "version_check"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+[[package]]
+name = "wasmtime-jit-icache-coherence"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6bbabb309c06cc238ee91b1455b748c45f0bdcab0dda2c2db85b0a1e69fcb66"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "windows-sys",
+]
+
[[package]]
name = "winapi"
version = "0.3.9"
version = "0.1.0"
edition = "2021"
+[[bin]]
+# This is used just to teach rust-analyzer how to check the build system. required-features is used
+# to disable it for regular builds.
+name = "y"
+path = "./y.rs"
+required-features = ["__check_build_system_using_ra"]
+
[lib]
crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { version = "0.88.1", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.88.1"
-cranelift-module = "0.88.1"
-cranelift-native = "0.88.1"
-cranelift-jit = { version = "0.88.1", optional = true }
-cranelift-object = "0.88.1"
+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"
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"] }
unstable-features = ["jit", "inline_asm"]
jit = ["cranelift-jit", "libloading"]
inline_asm = []
+__check_build_system_using_ra = []
[package.metadata.rust-analyzer]
rustc_private = true
In the directory with your project (where you can do the usual `cargo build`), run:
```bash
-$ $cg_clif_dir/build/cargo-clif build
+$ $cg_clif_dir/dist/cargo-clif build
```
This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
[[package]]
name = "addr2line"
-version = "0.16.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
+checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
dependencies = [
"compiler_builtins",
"gimli",
"core",
]
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
[[package]]
name = "cc"
-version = "1.0.73"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
-
-[[package]]
-name = "cfg-if"
-version = "0.1.10"
+version = "1.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
[[package]]
name = "cfg-if"
[[package]]
name = "compiler_builtins"
-version = "0.1.82"
+version = "0.1.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603"
+checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "gimli"
-version = "0.25.0"
+version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
+checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
[[package]]
name = "libc"
-version = "0.2.135"
+version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "miniz_oxide"
-version = "0.4.4"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
dependencies = [
"adler",
- "autocfg",
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
[[package]]
name = "object"
-version = "0.26.2"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
+checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
"compiler_builtins",
"memchr",
version = "0.0.0"
dependencies = [
"alloc",
- "cfg-if 0.1.10",
+ "cfg-if",
"compiler_builtins",
"core",
"libc",
version = "0.0.0"
dependencies = [
"alloc",
- "cfg-if 0.1.10",
+ "cfg-if",
"compiler_builtins",
"core",
"libc",
dependencies = [
"addr2line",
"alloc",
- "cfg-if 1.0.0",
+ "cfg-if",
"compiler_builtins",
"core",
"dlmalloc",
name = "std_detect"
version = "0.1.5"
dependencies = [
- "cfg-if 1.0.0",
+ "cfg-if",
"compiler_builtins",
"libc",
"rustc-std-workspace-alloc",
name = "test"
version = "0.0.0"
dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if",
"core",
"getopts",
"libc",
version = "0.0.0"
dependencies = [
"cc",
- "cfg-if 0.1.10",
+ "cfg-if",
"compiler_builtins",
"core",
"libc",
-use std::env;
use std::path::Path;
use super::build_sysroot;
use super::config;
-use super::prepare;
-use super::utils::{cargo_command, spawn_and_wait};
+use super::path::Dirs;
+use super::prepare::GitRepo;
+use super::utils::{spawn_and_wait, CargoProject, Compiler};
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) fn run(
channel: &str,
sysroot_kind: SysrootKind,
- target_dir: &Path,
+ dirs: &Dirs,
cg_clif_dylib: &Path,
host_triple: &str,
target_triple: &str,
eprintln!("Building sysroot for abi-cafe");
build_sysroot::build_sysroot(
+ dirs,
channel,
sysroot_kind,
- target_dir,
cg_clif_dylib,
host_triple,
target_triple,
);
eprintln!("Running abi-cafe");
- let abi_cafe_path = prepare::ABI_CAFE.source_dir();
- env::set_current_dir(abi_cafe_path.clone()).unwrap();
let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
- let mut cmd = cargo_command("cargo", "run", Some(target_triple), &abi_cafe_path);
+ let mut cmd = ABI_CAFE.run(&Compiler::host(), dirs);
cmd.arg("--");
cmd.arg("--pairs");
cmd.args(pairs);
cmd.arg("--add-rustc-codegen-backend");
cmd.arg(format!("cgclif:{}", cg_clif_dylib.display()));
+ cmd.current_dir(ABI_CAFE.source_dir(dirs));
spawn_and_wait(cmd);
}
use std::env;
use std::path::PathBuf;
+use super::path::{Dirs, RelPath};
use super::rustc_info::get_file_name;
-use super::utils::{cargo_command, is_ci};
+use super::utils::{is_ci, CargoProject, Compiler};
+
+static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
pub(crate) fn build_backend(
+ dirs: &Dirs,
channel: &str,
host_triple: &str,
use_unstable_features: bool,
) -> PathBuf {
- let source_dir = std::env::current_dir().unwrap();
- let mut cmd = cargo_command("cargo", "build", Some(host_triple), &source_dir);
+ let mut cmd = CG_CLIF.build(&Compiler::host(), dirs);
cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
eprintln!("[BUILD] rustc_codegen_cranelift");
super::utils::spawn_and_wait(cmd);
- source_dir
- .join("target")
+ CG_CLIF
+ .target_dir(dirs)
.join(host_triple)
.join(channel)
.join(get_file_name("rustc_codegen_cranelift", "dylib"))
use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::Path;
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::{cargo_command, spawn_and_wait, try_hard_link};
+use super::utils::{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,
- target_dir: &Path,
cg_clif_dylib_src: &Path,
host_triple: &str,
target_triple: &str,
) {
eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
- if target_dir.exists() {
- fs::remove_dir_all(target_dir).unwrap();
- }
- fs::create_dir_all(target_dir.join("bin")).unwrap();
- fs::create_dir_all(target_dir.join("lib")).unwrap();
+ DIST_DIR.ensure_fresh(dirs);
+ BIN_DIR.ensure_exists(dirs);
+ LIB_DIR.ensure_exists(dirs);
// Copy the backend
- let cg_clif_dylib_path = target_dir
- .join(if cfg!(windows) {
- // Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
- // binaries.
- "bin"
- } else {
- "lib"
- })
- .join(get_file_name("rustc_codegen_cranelift", "dylib"));
+ 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
+ // binaries.
+ BIN_DIR
+ } else {
+ LIB_DIR
+ }
+ .to_path(dirs)
+ .join(get_file_name("rustc_codegen_cranelift", "dylib"));
try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
// Build and copy rustc and cargo wrappers
- for wrapper in ["rustc-clif", "cargo-clif"] {
+ for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] {
let wrapper_name = get_wrapper_file_name(wrapper, "bin");
let mut build_cargo_wrapper_cmd = Command::new("rustc");
build_cargo_wrapper_cmd
- .arg(PathBuf::from("scripts").join(format!("{wrapper}.rs")))
+ .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
.arg("-o")
- .arg(target_dir.join(wrapper_name))
+ .arg(DIST_DIR.to_path(dirs).join(wrapper_name))
.arg("-g");
spawn_and_wait(build_cargo_wrapper_cmd);
}
let default_sysroot = super::rustc_info::get_default_sysroot();
- let rustlib = target_dir.join("lib").join("rustlib");
- let host_rustlib_lib = rustlib.join(host_triple).join("lib");
- let target_rustlib_lib = rustlib.join(target_triple).join("lib");
+ 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();
}
}
SysrootKind::Clif => {
- build_clif_sysroot_for_triple(
- channel,
- target_dir,
- host_triple,
- &cg_clif_dylib_path,
- None,
- );
+ build_clif_sysroot_for_triple(dirs, channel, host_triple, &cg_clif_dylib_path, None);
if host_triple != target_triple {
// When cross-compiling it is often necessary to manually pick the right linker
- let linker = if target_triple == "aarch64-unknown-linux-gnu" {
- Some("aarch64-linux-gnu-gcc")
- } else {
- None
+ 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_dir,
target_triple,
&cg_clif_dylib_path,
linker,
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, target_dir.join("lib").join(file.file_name().unwrap()));
+ try_hard_link(&file, LIB_DIR.to_path(dirs).join(file.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");
+
fn build_clif_sysroot_for_triple(
+ dirs: &Dirs,
channel: &str,
- target_dir: &Path,
triple: &str,
cg_clif_dylib_path: &Path,
linker: Option<&str>,
) {
- match fs::read_to_string(Path::new("build_sysroot").join("rustc_version")) {
+ match fs::read_to_string(SYSROOT_RUSTC_VERSION.to_path(dirs)) {
Err(e) => {
eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
eprintln!("Hint: Try `./y.rs prepare` to patch the sysroot source");
}
}
- let build_dir = Path::new("build_sysroot").join("target").join(triple).join(channel);
+ let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(triple).join(channel);
if !super::config::get_bool("keep_sysroot") {
// Cleanup the deps dir, but keep build scripts and the incremental cache for faster
}
// Build sysroot
- let mut build_cmd = cargo_command("cargo", "build", Some(triple), Path::new("build_sysroot"));
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={}", target_dir.to_str().unwrap()));
+ rustflags.push_str(&format!(" --sysroot={}", DIST_DIR.to_path(dirs).to_str().unwrap()));
if channel == "release" {
- build_cmd.arg("--release");
rustflags.push_str(" -Zmir-opt-level=3");
}
if let Some(linker) = linker {
use std::fmt::Write;
write!(rustflags, " -Clinker={}", linker).unwrap();
}
- build_cmd.env("RUSTFLAGS", rustflags);
+ let mut compiler = Compiler::with_triple(triple.to_owned());
+ compiler.rustflags = rustflags;
+ let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
+ if channel == "release" {
+ build_cmd.arg("--release");
+ }
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(Path::new("build_sysroot/target").join(triple).join(channel).join("deps"))
- .unwrap()
- {
+ for entry in fs::read_dir(build_dir.join("deps")).unwrap() {
let entry = entry.unwrap();
if let Some(ext) = entry.path().extension() {
if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" {
};
try_hard_link(
entry.path(),
- target_dir.join("lib").join("rustlib").join(triple).join("lib").join(entry.file_name()),
+ RUSTLIB_DIR.to_path(dirs).join(triple).join("lib").join(entry.file_name()),
);
}
}
mod build_backend;
mod build_sysroot;
mod config;
+mod path;
mod prepare;
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!(" ./y.rs prepare");
- eprintln!(
- " ./y.rs build [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
- );
- eprintln!(
- " ./y.rs test [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--no-unstable-features]"
- );
+ eprintln!("{USAGE}");
}
macro_rules! arg_error {
#[derive(PartialEq, Debug)]
enum Command {
+ Prepare,
Build,
Test,
}
pub fn main() {
env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
- // The target dir is expected in the default location. Guard against the user changing it.
- env::set_var("CARGO_TARGET_DIR", "target");
if is_ci() {
// Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
let mut args = env::args().skip(1);
let command = match args.next().as_deref() {
- Some("prepare") => {
- if args.next().is_some() {
- arg_error!("./y.rs prepare doesn't expect arguments");
- }
- prepare::prepare();
- process::exit(0);
- }
+ Some("prepare") => Command::Prepare,
Some("build") => Command::Build,
Some("test") => Command::Test,
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
}
};
- let mut target_dir = PathBuf::from("build");
+ let mut out_dir = PathBuf::from(".");
let mut channel = "release";
let mut sysroot_kind = SysrootKind::Clif;
let mut use_unstable_features = true;
while let Some(arg) = args.next().as_deref() {
match arg {
- "--target-dir" => {
- target_dir = PathBuf::from(args.next().unwrap_or_else(|| {
- arg_error!("--target-dir requires argument");
+ "--out-dir" => {
+ out_dir = PathBuf::from(args.next().unwrap_or_else(|| {
+ arg_error!("--out-dir requires argument");
}))
}
"--debug" => channel = "debug",
arg => arg_error!("Unexpected argument {}", arg),
}
}
- target_dir = std::env::current_dir().unwrap().join(target_dir);
let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
host_triple
host_triple.clone()
};
- let cg_clif_dylib = build_backend::build_backend(channel, &host_triple, use_unstable_features);
+ // FIXME allow changing the location of these dirs using cli arguments
+ let current_dir = std::env::current_dir().unwrap();
+ out_dir = current_dir.join(out_dir);
+ let dirs = path::Dirs {
+ source_dir: current_dir.clone(),
+ download_dir: out_dir.join("download"),
+ build_dir: out_dir.join("build"),
+ dist_dir: out_dir.join("dist"),
+ };
+
+ path::RelPath::BUILD.ensure_exists(&dirs);
+
+ {
+ // Make sure we always explicitly specify the target dir
+ let target =
+ path::RelPath::BUILD.join("target_dir_should_be_set_explicitly").to_path(&dirs);
+ env::set_var("CARGO_TARGET_DIR", &target);
+ let _ = std::fs::remove_file(&target);
+ std::fs::File::create(target).unwrap();
+ }
+
+ if command == Command::Prepare {
+ prepare::prepare(&dirs);
+ process::exit(0);
+ }
+
+ let cg_clif_dylib =
+ build_backend::build_backend(&dirs, channel, &host_triple, use_unstable_features);
match command {
+ Command::Prepare => {
+ // Handled above
+ }
Command::Test => {
tests::run_tests(
+ &dirs,
channel,
sysroot_kind,
- &target_dir,
&cg_clif_dylib,
&host_triple,
&target_triple,
abi_cafe::run(
channel,
sysroot_kind,
- &target_dir,
+ &dirs,
&cg_clif_dylib,
&host_triple,
&target_triple,
}
Command::Build => {
build_sysroot::build_sysroot(
+ &dirs,
channel,
sysroot_kind,
- &target_dir,
&cg_clif_dylib,
&host_triple,
&target_triple,
--- /dev/null
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Debug, Clone)]
+pub(crate) struct Dirs {
+ pub(crate) source_dir: PathBuf,
+ pub(crate) download_dir: PathBuf,
+ pub(crate) build_dir: PathBuf,
+ pub(crate) dist_dir: PathBuf,
+}
+
+#[doc(hidden)]
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum PathBase {
+ Source,
+ Download,
+ Build,
+ Dist,
+}
+
+impl PathBase {
+ fn to_path(self, dirs: &Dirs) -> PathBuf {
+ match self {
+ PathBase::Source => dirs.source_dir.clone(),
+ PathBase::Download => dirs.download_dir.clone(),
+ PathBase::Build => dirs.build_dir.clone(),
+ PathBase::Dist => dirs.dist_dir.clone(),
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum RelPath {
+ Base(PathBase),
+ Join(&'static RelPath, &'static str),
+}
+
+impl RelPath {
+ pub(crate) const SOURCE: RelPath = RelPath::Base(PathBase::Source);
+ pub(crate) const DOWNLOAD: RelPath = RelPath::Base(PathBase::Download);
+ pub(crate) const BUILD: RelPath = RelPath::Base(PathBase::Build);
+ 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 {
+ RelPath::Join(self, suffix)
+ }
+
+ pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
+ match self {
+ RelPath::Base(base) => base.to_path(dirs),
+ RelPath::Join(base, suffix) => base.to_path(dirs).join(suffix),
+ }
+ }
+
+ pub(crate) fn ensure_exists(&self, dirs: &Dirs) {
+ fs::create_dir_all(self.to_path(dirs)).unwrap();
+ }
+
+ pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
+ let path = self.to_path(dirs);
+ if path.exists() {
+ fs::remove_dir_all(&path).unwrap();
+ }
+ fs::create_dir_all(path).unwrap();
+ }
+}
-use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
+use super::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::{cargo_command, copy_dir_recursively, spawn_and_wait};
-
-pub(crate) const ABI_CAFE: GitRepo =
- GitRepo::github("Gankra", "abi-cafe", "4c6dc8c9c687e2b3a760ff2176ce236872b37212", "abi-cafe");
-
-pub(crate) const RAND: GitRepo =
- GitRepo::github("rust-random", "rand", "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", "rand");
-
-pub(crate) const REGEX: GitRepo =
- GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
-
-pub(crate) const PORTABLE_SIMD: GitRepo = GitRepo::github(
- "rust-lang",
- "portable-simd",
- "d5cd4a8112d958bd3a252327e0d069a6363249bd",
- "portable-simd",
-);
-
-pub(crate) const SIMPLE_RAYTRACER: GitRepo = GitRepo::github(
- "ebobby",
- "simple-raytracer",
- "804a7a21b9e673a482797aa289a18ed480e4d813",
- "<none>",
-);
-
-pub(crate) fn prepare() {
- if Path::new("download").exists() {
- std::fs::remove_dir_all(Path::new("download")).unwrap();
+use super::utils::{copy_dir_recursively, spawn_and_wait, Compiler};
+
+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(Path::new("download")).unwrap();
+ std::fs::create_dir_all(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
- prepare_sysroot();
+ prepare_sysroot(dirs);
// FIXME maybe install this only locally?
eprintln!("[INSTALL] hyperfine");
- Command::new("cargo").arg("install").arg("hyperfine").spawn().unwrap().wait().unwrap();
+ Command::new("cargo")
+ .arg("install")
+ .arg("hyperfine")
+ .env_remove("CARGO_TARGET_DIR")
+ .spawn()
+ .unwrap()
+ .wait()
+ .unwrap();
- ABI_CAFE.fetch();
- RAND.fetch();
- REGEX.fetch();
- PORTABLE_SIMD.fetch();
- SIMPLE_RAYTRACER.fetch();
+ super::abi_cafe::ABI_CAFE_REPO.fetch(dirs);
+ super::tests::RAND_REPO.fetch(dirs);
+ super::tests::REGEX_REPO.fetch(dirs);
+ super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
+ super::tests::SIMPLE_RAYTRACER_REPO.fetch(dirs);
eprintln!("[LLVM BUILD] simple-raytracer");
- let build_cmd = cargo_command("cargo", "build", None, &SIMPLE_RAYTRACER.source_dir());
+ let host_compiler = Compiler::host();
+ let build_cmd = super::tests::SIMPLE_RAYTRACER.build(&host_compiler, dirs);
spawn_and_wait(build_cmd);
fs::copy(
- SIMPLE_RAYTRACER
- .source_dir()
- .join("target")
+ super::tests::SIMPLE_RAYTRACER
+ .target_dir(dirs)
+ .join(&host_compiler.triple)
.join("debug")
.join(get_file_name("main", "bin")),
- SIMPLE_RAYTRACER.source_dir().join(get_file_name("raytracer_cg_llvm", "bin")),
+ RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
)
.unwrap();
}
-fn prepare_sysroot() {
+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 = env::current_dir().unwrap().join("build_sysroot").join("sysroot_src");
+ let sysroot_src = SYSROOT_SRC;
assert!(sysroot_src_orig.exists());
- if sysroot_src.exists() {
- fs::remove_dir_all(&sysroot_src).unwrap();
- }
- fs::create_dir_all(sysroot_src.join("library")).unwrap();
+ sysroot_src.ensure_fresh(dirs);
+ fs::create_dir_all(sysroot_src.to_path(dirs).join("library")).unwrap();
eprintln!("[COPY] sysroot src");
- copy_dir_recursively(&sysroot_src_orig.join("library"), &sysroot_src.join("library"));
+ copy_dir_recursively(
+ &sysroot_src_orig.join("library"),
+ &sysroot_src.to_path(dirs).join("library"),
+ );
let rustc_version = get_rustc_version();
- fs::write(Path::new("build_sysroot").join("rustc_version"), &rustc_version).unwrap();
+ fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
eprintln!("[GIT] init");
- let mut git_init_cmd = Command::new("git");
- git_init_cmd.arg("init").arg("-q").current_dir(&sysroot_src);
- spawn_and_wait(git_init_cmd);
-
- init_git_repo(&sysroot_src);
+ init_git_repo(&sysroot_src.to_path(dirs));
- apply_patches("sysroot", &sysroot_src);
+ apply_patches(dirs, "sysroot", &sysroot_src.to_path(dirs));
}
pub(crate) struct GitRepo {
}
impl GitRepo {
- const fn github(
+ pub(crate) const fn github(
user: &'static str,
repo: &'static str,
rev: &'static str,
GitRepo { url: GitRepoUrl::Github { user, repo }, rev, patch_name }
}
- pub(crate) fn source_dir(&self) -> PathBuf {
+ pub(crate) const fn source_dir(&self) -> RelPath {
match self.url {
- GitRepoUrl::Github { user: _, repo } => {
- std::env::current_dir().unwrap().join("download").join(repo)
- }
+ GitRepoUrl::Github { user: _, repo } => RelPath::DOWNLOAD.join(repo),
}
}
- fn fetch(&self) {
+ fn fetch(&self, dirs: &Dirs) {
match self.url {
GitRepoUrl::Github { user, repo } => {
- clone_repo_shallow_github(&self.source_dir(), user, repo, self.rev);
+ clone_repo_shallow_github(
+ dirs,
+ &self.source_dir().to_path(dirs),
+ user,
+ repo,
+ self.rev,
+ );
}
}
- apply_patches(self.patch_name, &self.source_dir());
+ apply_patches(dirs, self.patch_name, &self.source_dir().to_path(dirs));
}
}
spawn_and_wait(checkout_cmd);
}
-fn clone_repo_shallow_github(download_dir: &Path, user: &str, repo: &str, rev: &str) {
+fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo: &str, rev: &str) {
if cfg!(windows) {
// Older windows doesn't have tar or curl by default. Fall back to using git.
clone_repo(download_dir, &format!("https://github.com/{}/{}.git", user, repo), rev);
return;
}
- let downloads_dir = std::env::current_dir().unwrap().join("download");
-
let archive_url = format!("https://github.com/{}/{}/archive/{}.tar.gz", user, repo, rev);
- let archive_file = downloads_dir.join(format!("{}.tar.gz", rev));
- let archive_dir = downloads_dir.join(format!("{}-{}", repo, rev));
+ let archive_file = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}.tar.gz", rev));
+ let archive_dir = RelPath::DOWNLOAD.to_path(dirs).join(format!("{}-{}", repo, rev));
eprintln!("[DOWNLOAD] {}/{} from {}", user, repo, archive_url);
// Unpack tar archive
let mut unpack_cmd = Command::new("tar");
- unpack_cmd.arg("xf").arg(&archive_file).current_dir(downloads_dir);
+ unpack_cmd.arg("xf").arg(&archive_file).current_dir(RelPath::DOWNLOAD.to_path(dirs));
spawn_and_wait(unpack_cmd);
// Rename unpacked dir to the expected name
spawn_and_wait(git_add_cmd);
let mut git_commit_cmd = Command::new("git");
- git_commit_cmd.arg("commit").arg("-m").arg("Initial commit").arg("-q").current_dir(repo_dir);
+ 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);
spawn_and_wait(git_commit_cmd);
}
-fn get_patches(source_dir: &Path, crate_name: &str) -> Vec<PathBuf> {
- let mut patches: Vec<_> = fs::read_dir(source_dir.join("patches"))
+fn get_patches(dirs: &Dirs, crate_name: &str) -> Vec<PathBuf> {
+ let mut patches: Vec<_> = fs::read_dir(RelPath::PATCHES.to_path(dirs))
.unwrap()
.map(|entry| entry.unwrap().path())
.filter(|path| path.extension() == Some(OsStr::new("patch")))
patches
}
-fn apply_patches(crate_name: &str, target_dir: &Path) {
+fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
if crate_name == "<none>" {
return;
}
- for patch in get_patches(&std::env::current_dir().unwrap(), crate_name) {
+ for patch in get_patches(dirs, crate_name) {
eprintln!(
"[PATCH] {:?} <- {:?}",
target_dir.file_name().unwrap(),
patch.file_name().unwrap()
);
let mut apply_patch_cmd = Command::new("git");
- apply_patch_cmd.arg("am").arg(patch).arg("-q").current_dir(target_dir);
+ 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);
spawn_and_wait(apply_patch_cmd);
}
}
.to_owned()
}
+pub(crate) fn get_cargo_path() -> PathBuf {
+ let cargo_path = Command::new("rustup")
+ .stderr(Stdio::inherit())
+ .args(&["which", "cargo"])
+ .output()
+ .unwrap()
+ .stdout;
+ Path::new(String::from_utf8(cargo_path).unwrap().trim()).to_owned()
+}
+
pub(crate) fn get_rustc_path() -> PathBuf {
let rustc_path = Command::new("rustup")
.stderr(Stdio::inherit())
Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
}
+pub(crate) fn get_rustdoc_path() -> PathBuf {
+ let rustc_path = Command::new("rustup")
+ .stderr(Stdio::inherit())
+ .args(&["which", "rustdoc"])
+ .output()
+ .unwrap()
+ .stdout;
+ Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
+}
+
pub(crate) fn get_default_sysroot() -> PathBuf {
let default_sysroot = Command::new("rustc")
.stderr(Stdio::inherit())
use super::build_sysroot;
use super::config;
-use super::prepare;
-use super::rustc_info::get_wrapper_file_name;
-use super::utils::{cargo_command, hyperfine_command, spawn_and_wait, spawn_and_wait_with_input};
-use build_system::SysrootKind;
+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::SysrootKind;
use std::env;
use std::ffi::OsStr;
use std::fs;
-use std::path::{Path, PathBuf};
+use std::path::Path;
use std::process::Command;
+static BUILD_EXAMPLE_OUT_DIR: RelPath = RelPath::BUILD.join("example");
+
struct TestCase {
config: &'static str,
func: &'static dyn Fn(&TestRunner),
"--crate-type",
"lib,dylib",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
}),
TestCase::new("build.example", &|runner| {
"--crate-type",
"lib",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
}),
TestCase::new("jit.mini_core_hello_world", &|runner| {
"--cfg",
"jit",
"--target",
- &runner.host_triple,
+ &runner.target_compiler.triple,
]);
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
spawn_and_wait(jit_cmd);
"--cfg",
"jit",
"--target",
- &runner.host_triple,
+ &runner.target_compiler.triple,
]);
jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
spawn_and_wait(jit_cmd);
"bin",
"-g",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
}),
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
}),
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("issue_91827_extern_types", []);
}),
"--crate-type",
"lib",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
}),
TestCase::new("aot.alloc_example", &|runner| {
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("alloc_example", []);
}),
"-Cprefer-dynamic",
"example/std_example.rs",
"--target",
- &runner.host_triple,
+ &runner.target_compiler.triple,
]);
eprintln!("[JIT-lazy] std_example");
"-Cprefer-dynamic",
"example/std_example.rs",
"--target",
- &runner.host_triple,
+ &runner.target_compiler.triple,
]);
}),
TestCase::new("aot.std_example", &|runner| {
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("std_example", ["arg"]);
}),
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("dst_field_align", []);
}),
"bin",
"-Cpanic=abort",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("subslice-patterns-const-eval", []);
}),
"bin",
"-Cpanic=abort",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("track-caller-attribute", []);
}),
"bin",
"-Cpanic=abort",
"--target",
- &runner.target_triple,
+ &runner.target_compiler.triple,
]);
runner.run_out_command("float-minmax-pass", []);
}),
"--crate-type",
"bin",
"--target",
- &runner.target_triple,
+ &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", []);
+ }),
];
+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 REGEX_REPO: GitRepo =
+ GitRepo::github("rust-lang", "regex", "341f207c1071f7290e3f228c710817c280c8dca1", "regex");
+
+static REGEX: CargoProject = CargoProject::new(®EX_REPO.source_dir(), "regex");
+
+pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
+ "rust-lang",
+ "portable-simd",
+ "d5cd4a8112d958bd3a252327e0d069a6363249bd",
+ "portable-simd",
+);
+
+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");
+
const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
TestCase::new("test.rust-random/rand", &|runner| {
- runner.in_dir(prepare::RAND.source_dir(), |runner| {
- runner.run_cargo("clean", []);
-
- if runner.host_triple == runner.target_triple {
- eprintln!("[TEST] rust-random/rand");
- runner.run_cargo("test", ["--workspace"]);
- } else {
- eprintln!("[AOT] rust-random/rand");
- runner.run_cargo("build", ["--workspace", "--tests"]);
- }
- });
+ spawn_and_wait(RAND.clean(&runner.target_compiler.cargo, &runner.dirs));
+
+ if runner.is_native {
+ eprintln!("[TEST] rust-random/rand");
+ let mut test_cmd = RAND.test(&runner.target_compiler, &runner.dirs);
+ test_cmd.arg("--workspace");
+ spawn_and_wait(test_cmd);
+ } else {
+ eprintln!("[AOT] rust-random/rand");
+ let mut build_cmd = RAND.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--workspace").arg("--tests");
+ spawn_and_wait(build_cmd);
+ }
}),
TestCase::new("bench.simple-raytracer", &|runner| {
- runner.in_dir(prepare::SIMPLE_RAYTRACER.source_dir(), |runner| {
- let run_runs = env::var("RUN_RUNS").unwrap_or("10".to_string()).parse().unwrap();
-
- if runner.host_triple == runner.target_triple {
- eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
- let prepare = runner.cargo_command("clean", []);
-
- let llvm_build_cmd = cargo_command("cargo", "build", None, Path::new("."));
-
- let cargo_clif = runner
- .root_dir
- .clone()
- .join("build")
- .join(get_wrapper_file_name("cargo-clif", "bin"));
- let clif_build_cmd = cargo_command(cargo_clif, "build", None, Path::new("."));
-
- let bench_compile =
- hyperfine_command(1, run_runs, Some(prepare), llvm_build_cmd, clif_build_cmd);
-
- spawn_and_wait(bench_compile);
-
- eprintln!("[BENCH RUN] ebobby/simple-raytracer");
- fs::copy(PathBuf::from("./target/debug/main"), PathBuf::from("raytracer_cg_clif"))
- .unwrap();
-
- let bench_run = hyperfine_command(
- 0,
- run_runs,
- None,
- Command::new("./raytracer_cg_llvm"),
- Command::new("./raytracer_cg_clif"),
- );
- spawn_and_wait(bench_run);
- } else {
- runner.run_cargo("clean", []);
- eprintln!("[BENCH COMPILE] ebobby/simple-raytracer (skipped)");
- eprintln!("[COMPILE] ebobby/simple-raytracer");
- runner.run_cargo("build", []);
- eprintln!("[BENCH RUN] ebobby/simple-raytracer (skipped)");
- }
- });
+ 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::new("test.libcore", &|runner| {
- runner.in_dir(
- std::env::current_dir()
- .unwrap()
- .join("build_sysroot")
- .join("sysroot_src")
- .join("library")
- .join("core")
- .join("tests"),
- |runner| {
- runner.run_cargo("clean", []);
-
- if runner.host_triple == runner.target_triple {
- runner.run_cargo("test", []);
- } else {
- eprintln!("Cross-Compiling: Not running tests");
- runner.run_cargo("build", ["--tests"]);
- }
- },
- );
+ spawn_and_wait(LIBCORE_TESTS.clean(&runner.host_compiler.cargo, &runner.dirs));
+
+ if runner.is_native {
+ spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
+ } else {
+ eprintln!("Cross-Compiling: Not running tests");
+ let mut build_cmd = LIBCORE_TESTS.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--tests");
+ spawn_and_wait(build_cmd);
+ }
}),
TestCase::new("test.regex-shootout-regex-dna", &|runner| {
- runner.in_dir(prepare::REGEX.source_dir(), |runner| {
- runner.run_cargo("clean", []);
-
- // newer aho_corasick versions throw a deprecation warning
- let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
-
- let mut build_cmd = runner.cargo_command("build", ["--example", "shootout-regex-dna"]);
- build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
- spawn_and_wait(build_cmd);
-
- if runner.host_triple == runner.target_triple {
- let mut run_cmd = runner.cargo_command("run", ["--example", "shootout-regex-dna"]);
- run_cmd.env("RUSTFLAGS", lint_rust_flags);
-
- let input =
- fs::read_to_string(PathBuf::from("examples/regexdna-input.txt")).unwrap();
- let expected_path = PathBuf::from("examples/regexdna-output.txt");
- let expected = fs::read_to_string(&expected_path).unwrap();
-
- let output = spawn_and_wait_with_input(run_cmd, input);
- // Make sure `[codegen mono items] start` doesn't poison the diff
- let output = output
- .lines()
- .filter(|line| !line.contains("codegen mono items"))
- .chain(Some("")) // This just adds the trailing newline
- .collect::<Vec<&str>>()
- .join("\r\n");
-
- let output_matches = expected.lines().eq(output.lines());
- if !output_matches {
- let res_path = PathBuf::from("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);
- }
-
- std::process::exit(1);
+ spawn_and_wait(REGEX.clean(&runner.target_compiler.cargo, &runner.dirs));
+
+ // newer aho_corasick versions throw a deprecation warning
+ let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
+
+ let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--example").arg("shootout-regex-dna");
+ build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
+ spawn_and_wait(build_cmd);
+
+ if runner.is_native {
+ let mut run_cmd = REGEX.run(&runner.target_compiler, &runner.dirs);
+ run_cmd.arg("--example").arg("shootout-regex-dna");
+ run_cmd.env("RUSTFLAGS", lint_rust_flags);
+
+ let input = fs::read_to_string(
+ 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 output = spawn_and_wait_with_input(run_cmd, input);
+ // Make sure `[codegen mono items] start` doesn't poison the diff
+ let output = output
+ .lines()
+ .filter(|line| !line.contains("codegen mono items"))
+ .chain(Some("")) // This just adds the trailing newline
+ .collect::<Vec<&str>>()
+ .join("\r\n");
+
+ 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);
}
+
+ std::process::exit(1);
}
- });
+ }
}),
TestCase::new("test.regex", &|runner| {
- runner.in_dir(prepare::REGEX.source_dir(), |runner| {
- runner.run_cargo("clean", []);
-
- // newer aho_corasick versions throw a deprecation warning
- let lint_rust_flags = format!("{} --cap-lints warn", runner.rust_flags);
-
- if runner.host_triple == runner.target_triple {
- let mut run_cmd = runner.cargo_command(
- "test",
- [
- "--tests",
- "--",
- "--exclude-should-panic",
- "--test-threads",
- "1",
- "-Zunstable-options",
- "-q",
- ],
- );
- run_cmd.env("RUSTFLAGS", lint_rust_flags);
- spawn_and_wait(run_cmd);
- } else {
- eprintln!("Cross-Compiling: Not running tests");
- let mut build_cmd =
- runner.cargo_command("build", ["--tests", "--target", &runner.target_triple]);
- build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
- spawn_and_wait(build_cmd);
- }
- });
+ spawn_and_wait(REGEX.clean(&runner.host_compiler.cargo, &runner.dirs));
+
+ // newer aho_corasick versions throw a deprecation warning
+ let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
+
+ if runner.is_native {
+ let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
+ run_cmd.args([
+ "--tests",
+ "--",
+ "--exclude-should-panic",
+ "--test-threads",
+ "1",
+ "-Zunstable-options",
+ "-q",
+ ]);
+ run_cmd.env("RUSTFLAGS", lint_rust_flags);
+ spawn_and_wait(run_cmd);
+ } else {
+ eprintln!("Cross-Compiling: Not running tests");
+ let mut build_cmd = REGEX.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--tests");
+ build_cmd.env("RUSTFLAGS", lint_rust_flags.clone());
+ spawn_and_wait(build_cmd);
+ }
}),
TestCase::new("test.portable-simd", &|runner| {
- runner.in_dir(prepare::PORTABLE_SIMD.source_dir(), |runner| {
- runner.run_cargo("clean", []);
- runner.run_cargo("build", ["--all-targets", "--target", &runner.target_triple]);
+ spawn_and_wait(PORTABLE_SIMD.clean(&runner.host_compiler.cargo, &runner.dirs));
- if runner.host_triple == runner.target_triple {
- runner.run_cargo("test", ["-q"]);
- }
- });
+ let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
+ build_cmd.arg("--all-targets");
+ spawn_and_wait(build_cmd);
+
+ if runner.is_native {
+ let mut test_cmd = PORTABLE_SIMD.test(&runner.target_compiler, &runner.dirs);
+ test_cmd.arg("-q");
+ spawn_and_wait(test_cmd);
+ }
}),
];
pub(crate) fn run_tests(
+ dirs: &Dirs,
channel: &str,
sysroot_kind: SysrootKind,
- target_dir: &Path,
cg_clif_dylib: &Path,
host_triple: &str,
target_triple: &str,
) {
- let runner = TestRunner::new(host_triple.to_string(), target_triple.to_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(
+ dirs,
channel,
SysrootKind::None,
- &target_dir,
cg_clif_dylib,
&host_triple,
&target_triple,
);
- let _ = fs::remove_dir_all(Path::new("target").join("out"));
+ BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
runner.run_testsuite(NO_SYSROOT_SUITE);
} else {
eprintln!("[SKIP] no_sysroot tests");
if run_base_sysroot || run_extended_sysroot {
build_sysroot::build_sysroot(
+ dirs,
channel,
sysroot_kind,
- &target_dir,
cg_clif_dylib,
&host_triple,
&target_triple,
}
struct TestRunner {
- root_dir: PathBuf,
- out_dir: PathBuf,
+ is_native: bool,
jit_supported: bool,
- rust_flags: String,
- run_wrapper: Vec<String>,
- host_triple: String,
- target_triple: String,
+ dirs: Dirs,
+ host_compiler: Compiler,
+ target_compiler: Compiler,
}
impl TestRunner {
- pub fn new(host_triple: String, target_triple: String) -> Self {
- let root_dir = env::current_dir().unwrap();
-
- let mut out_dir = root_dir.clone();
- out_dir.push("target");
- out_dir.push("out");
-
+ 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 mut rust_flags = env::var("RUSTFLAGS").ok().unwrap_or("".to_string());
- let mut run_wrapper = Vec::new();
+ 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.
- rust_flags = format!("-Clinker=aarch64-linux-gnu-gcc{}", rust_flags);
- run_wrapper = vec!["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"];
+ 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.
- run_wrapper = vec!["wine"];
+ runner = vec!["wine".to_owned()];
}
_ => {
println!("Unknown non-native platform");
}
// FIXME fix `#[linkage = "extern_weak"]` without this
- if host_triple.contains("darwin") {
- rust_flags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rust_flags);
+ if target_triple.contains("darwin") {
+ rustflags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rustflags);
}
- Self {
- root_dir,
- out_dir,
- jit_supported,
- rust_flags,
- run_wrapper: run_wrapper.iter().map(|s| s.to_string()).collect(),
- host_triple,
- target_triple,
- }
+ 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 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 }
}
pub fn run_testsuite(&self, tests: &[TestCase]) {
}
}
- fn in_dir(&self, new: impl AsRef<Path>, callback: impl FnOnce(&TestRunner)) {
- let current = env::current_dir().unwrap();
-
- env::set_current_dir(new).unwrap();
- callback(self);
- env::set_current_dir(current).unwrap();
- }
-
+ #[must_use]
fn rustc_command<I, S>(&self, args: I) -> Command
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
- let mut rustc_clif = self.root_dir.clone();
- rustc_clif.push("build");
- rustc_clif.push(get_wrapper_file_name("rustc-clif", "bin"));
-
- let mut cmd = Command::new(rustc_clif);
- cmd.args(self.rust_flags.split_whitespace());
+ let mut cmd = Command::new(&self.target_compiler.rustc);
+ cmd.args(self.target_compiler.rustflags.split_whitespace());
cmd.arg("-L");
- cmd.arg(format!("crate={}", self.out_dir.display()));
+ cmd.arg(format!("crate={}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
cmd.arg("--out-dir");
- cmd.arg(format!("{}", self.out_dir.display()));
+ cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
cmd.arg("-Cdebuginfo=2");
cmd.args(args);
cmd
let mut full_cmd = vec![];
// Prepend the RUN_WRAPPER's
- if !self.run_wrapper.is_empty() {
- full_cmd.extend(self.run_wrapper.iter().cloned());
+ if !self.target_compiler.runner.is_empty() {
+ full_cmd.extend(self.target_compiler.runner.iter().cloned());
}
- full_cmd.push({
- let mut out_path = self.out_dir.clone();
- out_path.push(name);
- out_path.to_str().unwrap().to_string()
- });
+ full_cmd.push(
+ BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
+ );
for arg in args.into_iter() {
full_cmd.push(arg.to_string());
spawn_and_wait(cmd);
}
-
- fn cargo_command<'a, I>(&self, subcommand: &str, args: I) -> Command
- where
- I: IntoIterator<Item = &'a str>,
- {
- let mut cargo_clif = self.root_dir.clone();
- cargo_clif.push("build");
- cargo_clif.push(get_wrapper_file_name("cargo-clif", "bin"));
-
- let mut cmd = cargo_command(
- cargo_clif,
- subcommand,
- if subcommand == "clean" { None } else { Some(&self.target_triple) },
- Path::new("."),
- );
- cmd.args(args);
- cmd.env("RUSTFLAGS", &self.rust_flags);
- cmd
- }
-
- fn run_cargo<'a, I>(&self, subcommand: &str, args: I)
- where
- I: IntoIterator<Item = &'a str>,
- {
- spawn_and_wait(self.cargo_command(subcommand, args));
- }
}
use std::env;
use std::fs;
use std::io::Write;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
-pub(crate) fn cargo_command(
- cargo: impl AsRef<Path>,
- subcommand: &str,
- triple: Option<&str>,
- source_dir: &Path,
-) -> Command {
- let mut cmd = Command::new(cargo.as_ref());
- cmd.arg(subcommand)
- .arg("--manifest-path")
- .arg(source_dir.join("Cargo.toml"))
- .arg("--target-dir")
- .arg(source_dir.join("target"));
+use super::path::{Dirs, RelPath};
+use super::rustc_info::{get_cargo_path, get_host_triple, get_rustc_path, get_rustdoc_path};
+
+pub(crate) struct Compiler {
+ pub(crate) cargo: PathBuf,
+ pub(crate) rustc: PathBuf,
+ pub(crate) rustdoc: PathBuf,
+ pub(crate) rustflags: String,
+ pub(crate) rustdocflags: String,
+ pub(crate) triple: String,
+ pub(crate) runner: Vec<String>,
+}
+
+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 {
+ Compiler {
+ cargo: get_cargo_path(),
+ rustc: get_rustc_path(),
+ rustdoc: get_rustdoc_path(),
+ rustflags: String::new(),
+ rustdocflags: String::new(),
+ triple,
+ runner: vec![],
+ }
+ }
+}
+
+pub(crate) struct CargoProject {
+ source: &'static RelPath,
+ target: &'static str,
+}
+
+impl CargoProject {
+ pub(crate) const fn new(path: &'static RelPath, target: &'static str) -> CargoProject {
+ CargoProject { source: path, target }
+ }
+
+ pub(crate) fn source_dir(&self, dirs: &Dirs) -> PathBuf {
+ self.source.to_path(dirs)
+ }
+
+ pub(crate) fn manifest_path(&self, dirs: &Dirs) -> PathBuf {
+ self.source_dir(dirs).join("Cargo.toml")
+ }
+
+ pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf {
+ RelPath::BUILD.join(self.target).to_path(dirs)
+ }
- if let Some(triple) = triple {
- cmd.arg("--target").arg(triple);
+ fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
+ let mut cmd = Command::new(cargo);
+
+ cmd.arg(command)
+ .arg("--manifest-path")
+ .arg(self.manifest_path(dirs))
+ .arg("--target-dir")
+ .arg(self.target_dir(dirs));
+
+ cmd
+ }
+
+ fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command {
+ let mut cmd = self.base_cmd(command, &compiler.cargo, dirs);
+
+ cmd.arg("--target").arg(&compiler.triple);
+
+ cmd.env("RUSTC", &compiler.rustc);
+ cmd.env("RUSTDOC", &compiler.rustdoc);
+ cmd.env("RUSTFLAGS", &compiler.rustflags);
+ cmd.env("RUSTDOCFLAGS", &compiler.rustdocflags);
+ if !compiler.runner.is_empty() {
+ cmd.env(
+ format!("CARGO_TARGET_{}_RUNNER", compiler.triple.to_uppercase().replace('-', "_")),
+ compiler.runner.join(" "),
+ );
+ }
+
+ cmd
}
- cmd
+ #[must_use]
+ pub(crate) fn fetch(&self, cargo: impl AsRef<Path>, dirs: &Dirs) -> Command {
+ let mut cmd = Command::new(cargo.as_ref());
+
+ cmd.arg("fetch").arg("--manifest-path").arg(self.manifest_path(dirs));
+
+ cmd
+ }
+
+ #[must_use]
+ pub(crate) fn clean(&self, cargo: &Path, dirs: &Dirs) -> Command {
+ self.base_cmd("clean", cargo, dirs)
+ }
+
+ #[must_use]
+ pub(crate) fn build(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+ self.build_cmd("build", compiler, dirs)
+ }
+
+ #[must_use]
+ pub(crate) fn test(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+ self.build_cmd("test", compiler, dirs)
+ }
+
+ #[must_use]
+ pub(crate) fn run(&self, compiler: &Compiler, dirs: &Dirs) -> Command {
+ self.build_cmd("run", compiler, dirs)
+ }
}
+#[must_use]
pub(crate) fn hyperfine_command(
warmup: u64,
runs: u64,
- prepare: Option<Command>,
- a: Command,
- b: Command,
+ prepare: Option<&str>,
+ a: &str,
+ b: &str,
) -> Command {
let mut bench = Command::new("hyperfine");
}
if let Some(prepare) = prepare {
- bench.arg("--prepare").arg(format!("{:?}", prepare));
+ bench.arg("--prepare").arg(prepare);
}
- bench.arg(format!("{:?}", a)).arg(format!("{:?}", b));
+ bench.arg(a).arg(b);
bench
}
set -e
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
-rm -rf target/ build/ perf.data{,.old} y.bin
+rm -rf target/ build/ dist/ perf.data{,.old} y.bin
rm -rf download/
# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
aot.track-caller-attribute
aot.float-minmax-pass
aot.mod_bench
+aot.issue-72793
testsuite.extended_sysroot
test.rust-random/rand
In the directory with your project (where you can do the usual `cargo build`), run:
```bash
-$ $cg_clif_dir/build/cargo-clif build
+$ $cg_clif_dir/dist/cargo-clif build
```
This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend.
> You should prefer using the Cargo method.
```bash
-$ $cg_clif_dir/build/rustc-clif my_crate.rs
+$ $cg_clif_dir/dist/rustc-clif my_crate.rs
```
## Jit mode
> The jit mode will probably need cargo integration to make this possible.
```bash
-$ $cg_clif_dir/build/cargo-clif jit
+$ $cg_clif_dir/dist/cargo-clif jit
```
or
```bash
-$ $cg_clif_dir/build/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+$ $cg_clif_dir/dist/rustc-clif -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
```
There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
first called.
```bash
-$ $cg_clif_dir/build/cargo-clif lazy-jit
+$ $cg_clif_dir/dist/cargo-clif lazy-jit
```
## Shell
```bash
function jit_naked() {
- echo "$@" | $cg_clif_dir/build/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
+ echo "$@" | $cg_clif_dir/dist/rustc-clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
}
function jit() {
--- /dev/null
+// Adapted from rustc ui test suite (ui/type-alias-impl-trait/issue-72793.rs)
+
+#![feature(type_alias_impl_trait)]
+
+trait T { type Item; }
+
+type Alias<'a> = impl T<Item = &'a ()>;
+
+struct S;
+impl<'a> T for &'a S {
+ type Item = &'a ();
+}
+
+fn filter_positive<'a>() -> Alias<'a> {
+ &S
+}
+
+fn with_positive(fun: impl Fn(Alias<'_>)) {
+ fun(filter_positive());
+}
+
+fn main() {
+ with_positive(|_| ());
+}
#[lang = "destruct"]
pub trait Destruct {}
+#[lang = "tuple_trait"]
+pub trait Tuple {}
+
#[lang = "unsize"]
pub trait Unsize<T: ?Sized> {}
#[lang = "fn_once"]
#[rustc_paren_sugar]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: Tuple> {
#[lang = "fn_once_output"]
type Output;
#[lang = "fn_mut"]
#[rustc_paren_sugar]
-pub trait FnMut<Args>: FnOnce<Args> {
+pub trait FnMut<Args: Tuple>: FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
assert_eq!(slice_ptr as usize % 4, 0);
- //return;
-
unsafe {
printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
let cmp_eq = _mm_cmpeq_epi8(y, y);
let cmp_lt = _mm_cmplt_epi8(y, y);
+ let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x);
+ assert_eq!((zero0, zero1), (0, 0));
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
[toolchain]
-channel = "nightly-2022-10-23"
+channel = "nightly-2022-12-13"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
+ignore = ["y.rs"]
+
# Matches rustfmt.toml of rustc
version = "Two"
use_small_heuristics = "Max"
#![forbid(unsafe_code)]/* This line is ignored by bash
# This block is ignored by rustc
pushd $(dirname "$0")/../
-RUSTC="$(pwd)/build/rustc-clif"
+RUSTC="$(pwd)/dist/rustc-clif"
popd
PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -Cllvm-args=mode=jit -Cprefer-dynamic $0
#*/
--- /dev/null
+use std::env;
+use std::ffi::OsString;
+#[cfg(unix)]
+use std::os::unix::process::CommandExt;
+use std::path::PathBuf;
+use std::process::Command;
+
+fn main() {
+ let sysroot = PathBuf::from(env::current_exe().unwrap().parent().unwrap());
+
+ let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
+ env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
+ );
+
+ let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+ args.push(OsString::from("-Cpanic=abort"));
+ args.push(OsString::from("-Zpanic-abort-tests"));
+ let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
+ codegen_backend_arg.push(cg_clif_dylib_path);
+ args.push(codegen_backend_arg);
+ if !args.contains(&OsString::from("--sysroot")) {
+ args.push(OsString::from("--sysroot"));
+ args.push(OsString::from(sysroot.to_str().unwrap()));
+ }
+
+ // Ensure that the right toolchain is used
+ env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+
+ #[cfg(unix)]
+ Command::new("rustdoc").args(args).exec();
+
+ #[cfg(not(unix))]
+ std::process::exit(
+ Command::new("rustdoc").args(args).spawn().unwrap().wait().unwrap().code().unwrap_or(1),
+ );
+}
[dev-dependencies]
rand = "0.7"
rand_xorshift = "0.2"
-diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
-index 8431aa7b818..a3ff7e68ce5 100644
---- a/src/tools/compiletest/src/runtest.rs
-+++ b/src/tools/compiletest/src/runtest.rs
-@@ -3489,12 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
- let compiler_src_dir = base_dir.join("compiler");
- normalize_path(&compiler_src_dir, "$(echo '$COMPILER_DIR')");
-
-- if let Some(virtual_rust_source_base_dir) =
-- option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
-- {
-- normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')");
-- normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$(echo '$COMPILER_DIR')");
-- }
-+ normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')");
-
- // Paths into the build directory
- let test_build_dir = &self.config.build_base;
EOF
cat > config.toml <<EOF
ninja = false
[build]
-rustc = "$(pwd)/../build/rustc-clif"
+rustc = "$(pwd)/../dist/rustc-clif"
cargo = "$(rustup which cargo)"
full-bootstrap = true
local-rebuild = true
# 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)"
+
# Allow the testsuite to use llvm tools
host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin"
done
git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
+git checkout -- src/test/ui/proc-macro/pretty-print-hack/
# missing features
# ================
# requires compiling with -Cpanic=unwind
rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/
+rm -r src/test/run-make/test-benches
# vendor intrinsics
rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
rm -r src/test/run-make/emit-named-files # requires full --emit support
rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented
rm src/test/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
+rm -r src/test/run-make/repr128-dwarf # debuginfo test
+rm src/test/codegen-units/item-collection/asm-sym.rs # requires support for sym in asm!()
# optimization tests
# ==================
rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
rm src/test/ui/consts/issue-33537.rs # same
+rm src/test/ui/layout/valid_range_oob.rs # different ICE message
# 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
# ============================================================
-rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
+rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in dist/bin/
rm -r src/test/run-make/unstable-flag-required # same
rm -r src/test/run-make/rustdoc-* # same
rm -r src/test/run-make/issue-88756-default-output # same
rm -r src/test/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
+rm -r src/test/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to be elsewhere
# genuine bugs
# ============
-rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
-
rm src/test/incremental/spike-neg1.rs # errors out for some reason
rm src/test/incremental/spike-neg2.rs # same
rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
rm src/test/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
+rm src/test/ui/runtime/out-of-stack.rs # SIGSEGV instead of SIGABRT for some reason (#1301)
+
# bugs in the test suite
# ======================
rm src/test/ui/backtrace.rs # TODO warning
rm src/test/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 src/test/run-make/native-link-modifier-bundle
+rm src/test/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
+rm src/test/ui/dyn-star/dispatch-on-pin-mut.rs # TODO failed assertion in vtable::get_ptr_and_method_ref
rm src/test/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
pub(crate) fn get_function_sig<'tcx>(
tcx: TyCtxt<'tcx>,
- triple: &target_lexicon::Triple,
+ default_call_conv: CallConv,
inst: Instance<'tcx>,
) -> Signature {
assert!(!inst.substs.needs_infer());
clif_sig_from_fn_abi(
tcx,
- CallConv::triple_default(triple),
+ default_call_conv,
&RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
)
}
inst: Instance<'tcx>,
) -> FuncId {
let name = tcx.symbol_name(inst).name;
- let sig = get_function_sig(tcx, module.isa().triple(), inst);
+ let sig = get_function_sig(tcx, module.target_config().default_call_conv, inst);
match module.declare_function(name, Linkage::Import, &sig) {
Ok(func_id) => func_id,
Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
destination: Place<'tcx>,
target: Option<BasicBlock>,
) {
- let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
- let fn_sig =
- fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
+ let func = codegen_operand(fx, func);
+ let fn_sig = func.layout().ty.fn_sig(fx.tcx);
let ret_place = codegen_place(fx, destination);
// Handle special calls like intrinsics and empty drop glue.
- let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
+ let instance = if let ty::FnDef(def_id, substs) = *func.layout().ty.kind() {
let instance =
ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
.polymorphize(fx.tcx);
None
};
- let extra_args = &args[fn_sig.inputs().len()..];
+ let extra_args = &args[fn_sig.inputs().skip_binder().len()..];
let extra_args = fx
.tcx
.mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
let fn_abi = if let Some(instance) = instance {
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
} else {
- RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
+ RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
};
- let is_cold = if fn_sig.abi == Abi::RustCold {
+ let is_cold = if fn_sig.abi() == Abi::RustCold {
true
} else {
instance
}
// Unpack arguments tuple for closures
- let mut args = if fn_sig.abi == Abi::RustCall {
+ let mut args = if fn_sig.abi() == Abi::RustCall {
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
let self_arg = codegen_call_argument_operand(fx, &args[0]);
let pack_arg = codegen_call_argument_operand(fx, &args[1]);
fx.add_comment(nop_inst, "indirect call");
}
- let func = codegen_operand(fx, func).load_scalar(fx);
+ let func = func.load_scalar(fx);
let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
let sig = fx.bcx.import_signature(sig);
};
// FIXME find a cleaner way to support varargs
- if fn_sig.c_variadic {
- if !matches!(fn_sig.abi, Abi::C { .. }) {
+ if fn_sig.c_variadic() {
+ if !matches!(fn_sig.abi(), Abi::C { .. }) {
fx.tcx.sess.span_fatal(
source_info.span,
- &format!("Variadic call for non-C abi {:?}", fn_sig.abi),
+ &format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
);
}
let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
};
let sig = Signature {
- call_conv: CallConv::triple_default(module.isa().triple()),
+ call_conv: module.target_config().default_call_conv,
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
returns: output.into_iter().map(AbiParam::new).collect(),
};
}
let sig = Signature {
- call_conv: CallConv::triple_default(module.isa().triple()),
+ call_conv: module.target_config().default_call_conv,
params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
returns: vec![],
};
// Declare function
let symbol_name = tcx.symbol_name(instance).name.to_string();
- let sig = get_function_sig(tcx, module.isa().triple(), instance);
+ let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance);
let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
// Make the FunctionBuilder
_ => unreachable!("{:?}", targets),
};
- let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
let (discr, is_inverted) =
crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr);
let test_zero = if is_inverted { !test_zero } else { test_zero };
- let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
&fx.bcx, discr, test_zero,
) {
UnOp::Not => match layout.ty.kind() {
ty::Bool => {
let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0);
- CValue::by_val(fx.bcx.ins().bint(types::I8, res), layout)
+ CValue::by_val(res, layout)
}
ty::Uint(_) | ty::Int(_) => {
CValue::by_val(fx.bcx.ins().bnot(val), layout)
_ => unreachable!("un op Not for {:?}", layout.ty),
},
UnOp::Neg => match layout.ty.kind() {
- ty::Int(IntTy::I128) => {
- // FIXME remove this case once ineg.i128 works
- let zero =
- CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
- crate::num::codegen_int_binop(fx, BinOp::Sub, zero, operand)
- }
ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout),
ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout),
_ => unreachable!("un op Neg for {:?}", layout.ty),
}
let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
- let zero = fx.bcx.ins().iconst(to_ty, 0);
+ let zero = type_zero_value(&mut fx.bcx, to_ty);
fx.bcx.ins().select(is_not_nan, val, zero)
} else if from_ty.is_float() && to_ty.is_float() {
// float -> float
}
}
} else {
- let rhs = i64::try_from(rhs).expect("codegen_icmp_imm rhs out of range for <128bit int");
+ let rhs = rhs as i64; // Truncates on purpose in case rhs is actually an unsigned value
fx.bcx.ins().icmp_imm(intcc, lhs, rhs)
}
}
+pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value {
+ if ty == types::I128 {
+ let zero = bcx.ins().iconst(types::I64, 0);
+ bcx.ins().iconcat(zero, zero)
+ } else {
+ bcx.ins().iconst(ty, 0)
+ }
+}
+
pub(crate) fn type_min_max_value(
bcx: &mut FunctionBuilder<'_>,
ty: Type,
}
pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) {
- //println!("todo {:?}", self.todo);
define_all_allocs(tcx, module, &mut self);
- //println!("done {:?}", self.done);
self.done.clear();
}
}
def_id: DefId,
definition: bool,
) -> DataId {
- let rlinkage = tcx.codegen_fn_attrs(def_id).linkage;
- let linkage = if definition {
- crate::linkage::get_static_linkage(tcx, def_id)
- } else if rlinkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
- || rlinkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
- {
- Linkage::Preemptible
- } else {
- Linkage::Import
- };
+ let attrs = tcx.codegen_fn_attrs(def_id);
let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
let symbol_name = tcx.symbol_name(instance).name;
};
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
- let attrs = tcx.codegen_fn_attrs(def_id);
+ if let Some(import_linkage) = attrs.import_linkage {
+ assert!(!definition);
- let data_id = match module.declare_data(
- &*symbol_name,
- linkage,
- is_mutable,
- attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
- ) {
- Ok(data_id) => data_id,
- Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
- "attempt to declare `{symbol_name}` as static, but it was already declared as function"
- )),
- Err(err) => Err::<_, _>(err).unwrap(),
- };
+ let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak
+ || import_linkage == rustc_middle::mir::mono::Linkage::WeakAny
+ {
+ Linkage::Preemptible
+ } else {
+ Linkage::Import
+ };
+
+ let data_id = match module.declare_data(
+ &*symbol_name,
+ linkage,
+ is_mutable,
+ attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
+ ) {
+ Ok(data_id) => data_id,
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ "attempt to declare `{symbol_name}` as static, but it was already declared as function"
+ )),
+ Err(err) => Err::<_, _>(err).unwrap(),
+ };
- if rlinkage.is_some() {
// Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141
// Declare an internal global `extern_with_linkage_foo` which
// is initialized with the address of `foo`. If `foo` is
Err(ModuleError::DuplicateDefinition(_)) => {}
res => res.unwrap(),
}
- ref_data_id
- } else {
- data_id
+
+ return ref_data_id;
}
+
+ let linkage = if definition {
+ crate::linkage::get_static_linkage(tcx, def_id)
+ } else if attrs.linkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak)
+ || attrs.linkage == Some(rustc_middle::mir::mono::Linkage::WeakAny)
+ {
+ Linkage::Preemptible
+ } else {
+ Linkage::Import
+ };
+
+ let data_id = match module.declare_data(
+ &*symbol_name,
+ linkage,
+ is_mutable,
+ attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
+ ) {
+ Ok(data_id) => data_id,
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ "attempt to declare `{symbol_name}` as static, but it was already declared as function"
+ )),
+ Err(err) => Err::<_, _>(err).unwrap(),
+ };
+
+ data_id
}
fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) {
(data_id, alloc, None)
}
TodoItem::Static(def_id) => {
- //println!("static {:?}", def_id);
-
let section_name = tcx.codegen_fn_attrs(def_id).link_section;
let alloc = tcx.eval_static_initializer(def_id).unwrap();
}
};
- //("data_id {}", data_id);
if cx.done.contains(&data_id) {
continue;
}
}
pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
- let unwind_info = if let Some(unwind_info) = context.create_unwind_info(isa).unwrap() {
+ let unwind_info = if let Some(unwind_info) =
+ context.compiled_code().unwrap().create_unwind_info(isa).unwrap()
+ {
unwind_info
} else {
return;
//! Handling of enum discriminants
//!
-//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>
+//! Adapted from <https://github.com/rust-lang/rust/blob/31c0645b9d2539f47eecb096142474b29dc542f7/compiler/rustc_codegen_ssa/src/mir/place.rs>
+//! (<https://github.com/rust-lang/rust/pull/104535>)
use rustc_target::abi::{Int, TagEncoding, Variants};
} => {
if variant_index != untagged_variant {
let niche = place.place_field(fx, mir::Field::new(tag_field));
+ let niche_type = fx.clif_type(niche.layout().ty).unwrap();
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
- let niche_value = ty::ScalarInt::try_from_uint(
- u128::from(niche_value).wrapping_add(niche_start),
- niche.layout().size,
- )
- .unwrap();
- let niche_llval = CValue::const_val(fx, niche.layout(), niche_value);
+ let niche_value = (niche_value as u128).wrapping_add(niche_start);
+ let niche_value = match niche_type {
+ types::I128 => {
+ let lsb = fx.bcx.ins().iconst(types::I64, niche_value as u64 as i64);
+ let msb =
+ fx.bcx.ins().iconst(types::I64, (niche_value >> 64) as u64 as i64);
+ fx.bcx.ins().iconcat(lsb, msb)
+ }
+ ty => fx.bcx.ins().iconst(ty, niche_value as i64),
+ };
+ let niche_llval = CValue::by_val(niche_value, niche.layout());
niche.write_cvalue(fx, niche_llval);
}
}
}
};
+ let cast_to_size = dest_layout.layout.size();
let cast_to = fx.clif_type(dest_layout.ty).unwrap();
// Read the tag/niche-encoded discriminant from memory.
dest.write_cvalue(fx, res);
}
TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
- // Rebase from niche values to discriminants, and check
- // whether the result is in range for the niche variants.
-
- // We first compute the "relative discriminant" (wrt `niche_variants`),
- // that is, if `n = niche_variants.end() - niche_variants.start()`,
- // we remap `niche_start..=niche_start + n` (which may wrap around)
- // to (non-wrap-around) `0..=n`, to be able to check whether the
- // discriminant corresponds to a niche variant with one comparison.
- // We also can't go directly to the (variant index) discriminant
- // and check that it is in the range `niche_variants`, because
- // that might not fit in the same type, on top of needing an extra
- // comparison (see also the comment on `let niche_discr`).
- let relative_discr = if niche_start == 0 {
- tag
+ let tag_size = tag_scalar.size(fx);
+ let max_unsigned = tag_size.unsigned_int_max();
+ let max_signed = tag_size.signed_int_max() as u128;
+ let min_signed = max_signed + 1;
+ let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
+ let niche_end = niche_start.wrapping_add(relative_max as u128) & max_unsigned;
+ let range = tag_scalar.valid_range(fx);
+
+ let sle = |lhs: u128, rhs: u128| -> bool {
+ // Signed and unsigned comparisons give the same results,
+ // except that in signed comparisons an integer with the
+ // sign bit set is less than one with the sign bit clear.
+ // Toggle the sign bit to do a signed comparison.
+ (lhs ^ min_signed) <= (rhs ^ min_signed)
+ };
+
+ // We have a subrange `niche_start..=niche_end` inside `range`.
+ // If the value of the tag is inside this subrange, it's a
+ // "niche value", an increment of the discriminant. Otherwise it
+ // indicates the untagged variant.
+ // A general algorithm to extract the discriminant from the tag
+ // is:
+ // relative_tag = tag - niche_start
+ // is_niche = relative_tag <= (ule) relative_max
+ // discr = if is_niche {
+ // cast(relative_tag) + niche_variants.start()
+ // } else {
+ // untagged_variant
+ // }
+ // However, we will likely be able to emit simpler code.
+
+ // Find the least and greatest values in `range`, considered
+ // both as signed and unsigned.
+ let (low_unsigned, high_unsigned) =
+ if range.start <= range.end { (range.start, range.end) } else { (0, max_unsigned) };
+ let (low_signed, high_signed) = if sle(range.start, range.end) {
+ (range.start, range.end)
} else {
+ (min_signed, max_signed)
+ };
+
+ let niches_ule = niche_start <= niche_end;
+ let niches_sle = sle(niche_start, niche_end);
+ let cast_smaller = cast_to_size <= tag_size;
+
+ // In the algorithm above, we can change
+ // cast(relative_tag) + niche_variants.start()
+ // into
+ // cast(tag + (niche_variants.start() - niche_start))
+ // if either the casted type is no larger than the original
+ // type, or if the niche values are contiguous (in either the
+ // signed or unsigned sense).
+ let can_incr = cast_smaller || niches_ule || niches_sle;
+
+ let data_for_boundary_niche = || -> Option<(IntCC, u128)> {
+ if !can_incr {
+ None
+ } else if niche_start == low_unsigned {
+ Some((IntCC::UnsignedLessThanOrEqual, niche_end))
+ } else if niche_end == high_unsigned {
+ Some((IntCC::UnsignedGreaterThanOrEqual, niche_start))
+ } else if niche_start == low_signed {
+ Some((IntCC::SignedLessThanOrEqual, niche_end))
+ } else if niche_end == high_signed {
+ Some((IntCC::SignedGreaterThanOrEqual, niche_start))
+ } else {
+ None
+ }
+ };
+
+ let (is_niche, tagged_discr, delta) = if relative_max == 0 {
+ // Best case scenario: only one tagged variant. This will
+ // likely become just a comparison and a jump.
+ // The algorithm is:
+ // is_niche = tag == niche_start
+ // discr = if is_niche {
+ // niche_start
+ // } else {
+ // untagged_variant
+ // }
+ let is_niche = codegen_icmp_imm(fx, IntCC::Equal, tag, niche_start as i128);
+ let tagged_discr =
+ fx.bcx.ins().iconst(cast_to, niche_variants.start().as_u32() as i64);
+ (is_niche, tagged_discr, 0)
+ } else if let Some((predicate, constant)) = data_for_boundary_niche() {
+ // The niche values are either the lowest or the highest in
+ // `range`. We can avoid the first subtraction in the
+ // algorithm.
+ // The algorithm is now this:
+ // is_niche = tag <= niche_end
+ // discr = if is_niche {
+ // cast(tag + (niche_variants.start() - niche_start))
+ // } else {
+ // untagged_variant
+ // }
+ // (the first line may instead be tag >= niche_start,
+ // and may be a signed or unsigned comparison)
+ // The arithmetic must be done before the cast, so we can
+ // have the correct wrapping behavior. See issue #104519 for
+ // the consequences of getting this wrong.
+ let is_niche = codegen_icmp_imm(fx, predicate, tag, constant as i128);
+ let delta = (niche_variants.start().as_u32() as u128).wrapping_sub(niche_start);
+ let incr_tag = if delta == 0 {
+ tag
+ } else {
+ let delta = match fx.bcx.func.dfg.value_type(tag) {
+ types::I128 => {
+ let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64);
+ let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64);
+ fx.bcx.ins().iconcat(lsb, msb)
+ }
+ ty => fx.bcx.ins().iconst(ty, delta as i64),
+ };
+ fx.bcx.ins().iadd(tag, delta)
+ };
+
+ let cast_tag = clif_intcast(fx, incr_tag, cast_to, !niches_ule);
+
+ (is_niche, cast_tag, 0)
+ } else {
+ // The special cases don't apply, so we'll have to go with
+ // the general algorithm.
let niche_start = match fx.bcx.func.dfg.value_type(tag) {
types::I128 => {
let lsb = fx.bcx.ins().iconst(types::I64, niche_start as u64 as i64);
}
ty => fx.bcx.ins().iconst(ty, niche_start as i64),
};
- fx.bcx.ins().isub(tag, niche_start)
- };
- let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
- let is_niche = {
- codegen_icmp_imm(
+ let relative_discr = fx.bcx.ins().isub(tag, niche_start);
+ let cast_tag = clif_intcast(fx, relative_discr, cast_to, false);
+ let is_niche = crate::common::codegen_icmp_imm(
fx,
IntCC::UnsignedLessThanOrEqual,
relative_discr,
i128::from(relative_max),
- )
+ );
+ (is_niche, cast_tag, niche_variants.start().as_u32() as u128)
};
- // NOTE(eddyb) this addition needs to be performed on the final
- // type, in case the niche itself can't represent all variant
- // indices (e.g. `u8` niche with more than `256` variants,
- // but enough uninhabited variants so that the remaining variants
- // fit in the niche).
- // In other words, `niche_variants.end - niche_variants.start`
- // is representable in the niche, but `niche_variants.end`
- // might not be, in extreme cases.
- let niche_discr = {
- let relative_discr = if relative_max == 0 {
- // HACK(eddyb) since we have only one niche, we know which
- // one it is, and we can avoid having a dynamic value here.
- fx.bcx.ins().iconst(cast_to, 0)
- } else {
- clif_intcast(fx, relative_discr, cast_to, false)
+ let tagged_discr = if delta == 0 {
+ tagged_discr
+ } else {
+ let delta = match cast_to {
+ types::I128 => {
+ let lsb = fx.bcx.ins().iconst(types::I64, delta as u64 as i64);
+ let msb = fx.bcx.ins().iconst(types::I64, (delta >> 64) as u64 as i64);
+ fx.bcx.ins().iconcat(lsb, msb)
+ }
+ ty => fx.bcx.ins().iconst(ty, delta as i64),
};
- fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
+ fx.bcx.ins().iadd(tagged_discr, delta)
};
- let untagged_variant =
- fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()));
- let discr = fx.bcx.ins().select(is_niche, niche_discr, untagged_variant);
+ let untagged_variant = if cast_to == types::I128 {
+ let zero = fx.bcx.ins().iconst(types::I64, 0);
+ let untagged_variant =
+ fx.bcx.ins().iconst(types::I64, i64::from(untagged_variant.as_u32()));
+ fx.bcx.ins().iconcat(untagged_variant, zero)
+ } else {
+ fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()))
+ };
+ let discr = fx.bcx.ins().select(is_niche, tagged_discr, untagged_variant);
let res = CValue::by_val(discr, dest_layout);
dest.write_cvalue(fx, res);
}
tcx.sess.abort_if_errors();
- jit_module.finalize_definitions();
+ jit_module.finalize_definitions().unwrap();
unsafe { cx.unwind_context.register_jit(&jit_module) };
println!(
let backend_config = lazy_jit_state.backend_config.clone();
let name = tcx.symbol_name(instance).name;
- let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
+ let sig = crate::abi::get_function_sig(
+ tcx,
+ jit_module.target_config().default_call_conv,
+ instance,
+ );
let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
let current_ptr = jit_module.read_got_entry(func_id);
});
assert!(cx.global_asm.is_empty());
- jit_module.finalize_definitions();
+ jit_module.finalize_definitions().unwrap();
unsafe { cx.unwind_context.register_jit(&jit_module) };
jit_module.get_finalized_function(func_id)
})
let pointer_type = module.target_config().pointer_type();
let name = tcx.symbol_name(inst).name;
- let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
+ let sig = crate::abi::get_function_sig(tcx, module.target_config().default_call_conv, inst);
let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
let instance_ptr = Box::into_raw(Box::new(inst));
MonoItem::Fn(instance) => {
let name = tcx.symbol_name(instance).name;
let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name));
- let sig = get_function_sig(tcx, module.isa().triple(), instance);
+ let sig =
+ get_function_sig(tcx, module.target_config().default_call_conv, instance);
let linkage = crate::linkage::get_clif_linkage(
mono_item,
linkage,
pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
intrinsic: &str,
- _substs: SubstsRef<'tcx>,
+ substs: SubstsRef<'tcx>,
args: &[mir::Operand<'tcx>],
ret: CPlace<'tcx>,
target: Option<BasicBlock>,
) {
- match intrinsic {
- "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
- // Spin loop hint
- }
+ if intrinsic.starts_with("llvm.aarch64") {
+ return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(
+ fx, intrinsic, substs, args, ret, target,
+ );
+ }
+ if intrinsic.starts_with("llvm.x86") {
+ return llvm_x86::codegen_x86_llvm_intrinsic_call(fx, intrinsic, substs, args, ret, target);
+ }
- // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
- "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
+ match intrinsic {
+ _ if intrinsic.starts_with("llvm.ctlz.v") => {
intrinsic_args!(fx, args => (a); intrinsic);
- let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
- let lane_ty = fx.clif_type(lane_ty).unwrap();
- assert!(lane_count <= 32);
-
- let mut res = fx.bcx.ins().iconst(types::I32, 0);
-
- for lane in (0..lane_count).rev() {
- let a_lane = a.value_lane(fx, lane).load_scalar(fx);
-
- // 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),
- _ => a_lane,
- };
-
- // extract sign bit of an int
- let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
-
- // shift sign bit into result
- let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
- res = fx.bcx.ins().ishl_imm(res, 1);
- res = fx.bcx.ins().bor(res, a_lane_sign);
- }
-
- let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
- ret.write_cvalue(fx, res);
- }
- "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
- let (x, y, kind) = match args {
- [x, y, kind] => (x, y, kind),
- _ => bug!("wrong number of args for intrinsic {intrinsic}"),
- };
- let x = codegen_operand(fx, x);
- let y = codegen_operand(fx, y);
- let kind = crate::constant::mir_operand_get_const_val(fx, kind)
- .expect("llvm.x86.sse2.cmp.* kind not const");
-
- let flt_cc = match kind
- .try_to_bits(Size::from_bytes(1))
- .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
- {
- 0 => FloatCC::Equal,
- 1 => FloatCC::LessThan,
- 2 => FloatCC::LessThanOrEqual,
- 7 => FloatCC::Ordered,
- 3 => FloatCC::Unordered,
- 4 => FloatCC::NotEqual,
- 5 => FloatCC::UnorderedOrGreaterThanOrEqual,
- 6 => FloatCC::UnorderedOrGreaterThan,
- kind => unreachable!("kind {:?}", kind),
- };
-
- simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
- let res_lane = match lane_ty.kind() {
- ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
- _ => unreachable!("{:?}", lane_ty),
- };
- bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().clz(lane)
});
}
- "llvm.x86.sse2.psrli.d" => {
- let (a, imm8) = match args {
- [a, imm8] => (a, imm8),
- _ => bug!("wrong number of args for intrinsic {intrinsic}"),
- };
- let a = codegen_operand(fx, a);
- let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
- .expect("llvm.x86.sse2.psrli.d imm8 not const");
- simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
- .try_to_bits(Size::from_bytes(4))
- .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
- {
- imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
- _ => fx.bcx.ins().iconst(types::I32, 0),
- });
- }
- "llvm.x86.sse2.pslli.d" => {
- let (a, imm8) = match args {
- [a, imm8] => (a, imm8),
- _ => bug!("wrong number of args for intrinsic {intrinsic}"),
- };
- let a = codegen_operand(fx, a);
- let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
- .expect("llvm.x86.sse2.psrli.d imm8 not const");
+ _ if intrinsic.starts_with("llvm.ctpop.v") => {
+ intrinsic_args!(fx, args => (a); intrinsic);
- simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
- .try_to_bits(Size::from_bytes(4))
- .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
- {
- imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
- _ => fx.bcx.ins().iconst(types::I32, 0),
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().popcnt(lane)
});
}
- "llvm.x86.sse2.storeu.dq" => {
- intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
- let mem_addr = mem_addr.load_scalar(fx);
-
- // FIXME correctly handle the unalignment
- let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
- dest.write_cvalue(fx, a);
- }
- "llvm.x86.addcarry.64" => {
- intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
- let c_in = c_in.load_scalar(fx);
-
- llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
- }
- "llvm.x86.subborrow.64" => {
- intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
- let b_in = b_in.load_scalar(fx);
- llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
- }
_ => {
fx.tcx
.sess
let ret_block = fx.get_block(dest);
fx.bcx.ins().jump(ret_block, &[]);
}
-
-// llvm.x86.avx2.vperm2i128
-// llvm.x86.ssse3.pshuf.b.128
-// llvm.x86.avx2.pshuf.b
-// llvm.x86.avx2.psrli.w
-// llvm.x86.sse2.psrli.w
-
-fn llvm_add_sub<'tcx>(
- fx: &mut FunctionCx<'_, '_, 'tcx>,
- bin_op: BinOp,
- ret: CPlace<'tcx>,
- cb_in: Value,
- a: CValue<'tcx>,
- b: CValue<'tcx>,
-) {
- assert_eq!(
- a.layout().ty,
- fx.tcx.types.u64,
- "llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
- );
- assert_eq!(
- b.layout().ty,
- fx.tcx.types.u64,
- "llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
- );
-
- // c + carry -> c + first intermediate carry or borrow respectively
- let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
- let c = int0.value_field(fx, mir::Field::new(0));
- let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
-
- // c + carry -> c + second intermediate carry or borrow respectively
- let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
- let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
- let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
- let (c, cb1) = int1.load_scalar_pair(fx);
-
- // carry0 | carry1 -> carry or borrow respectively
- let cb_out = fx.bcx.ins().bor(cb0, cb1);
-
- let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
- let val = CValue::by_val_pair(cb_out, c, layout);
- ret.write_cvalue(fx, val);
-}
--- /dev/null
+//! Emulate AArch64 LLVM intrinsics
+
+use crate::intrinsics::*;
+use crate::prelude::*;
+
+use rustc_middle::ty::subst::SubstsRef;
+
+pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ intrinsic: &str,
+ _substs: SubstsRef<'tcx>,
+ args: &[mir::Operand<'tcx>],
+ ret: CPlace<'tcx>,
+ target: Option<BasicBlock>,
+) {
+ // llvm.aarch64.neon.sqshl.v*i*
+
+ match intrinsic {
+ "llvm.aarch64.isb" => {
+ fx.bcx.ins().fence();
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.abs.v") => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().iabs(lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.cls.v") => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().cls(lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.rbit.v") => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
+ fx.bcx.ins().bitrev(lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sqadd.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
+ crate::num::codegen_saturating_int_binop(fx, BinOp::Add, x_lane, y_lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sqsub.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane_typed(fx, x, y, ret, &|fx, x_lane, y_lane| {
+ crate::num::codegen_saturating_int_binop(fx, BinOp::Sub, x_lane, y_lane)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.smax.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane(
+ fx,
+ x,
+ y,
+ ret,
+ &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+ let gt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, x_lane, y_lane);
+ fx.bcx.ins().select(gt, x_lane, y_lane)
+ },
+ );
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.umax.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane(
+ fx,
+ x,
+ y,
+ ret,
+ &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+ let gt = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, x_lane, y_lane);
+ fx.bcx.ins().select(gt, x_lane, y_lane)
+ },
+ );
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.smaxv.i") => {
+ intrinsic_args!(fx, args => (v); intrinsic);
+
+ simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+ let gt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.umaxv.i") => {
+ intrinsic_args!(fx, args => (v); intrinsic);
+
+ simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+ let gt = fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.smin.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane(
+ fx,
+ x,
+ y,
+ ret,
+ &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+ let gt = fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane);
+ fx.bcx.ins().select(gt, x_lane, y_lane)
+ },
+ );
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.umin.v") => {
+ intrinsic_args!(fx, args => (x, y); intrinsic);
+
+ simd_pair_for_each_lane(
+ fx,
+ x,
+ y,
+ ret,
+ &|fx, _lane_ty, _res_lane_ty, x_lane, y_lane| {
+ let gt = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane);
+ fx.bcx.ins().select(gt, x_lane, y_lane)
+ },
+ );
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sminv.i") => {
+ intrinsic_args!(fx, args => (v); intrinsic);
+
+ simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+ let gt = fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.uminv.i") => {
+ intrinsic_args!(fx, args => (v); intrinsic);
+
+ simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| {
+ let gt = fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ }
+
+ /*
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sshl.v")
+ || intrinsic.starts_with("llvm.aarch64.neon.sqshl.v")
+ // FIXME split this one out once saturating is implemented
+ || intrinsic.starts_with("llvm.aarch64.neon.sqshlu.v") =>
+ {
+ intrinsic_args!(fx, args => (a, b); intrinsic);
+
+ simd_pair_for_each_lane(fx, a, b, ret, &|fx, _lane_ty, _res_lane_ty, a, b| {
+ // FIXME saturate?
+ fx.bcx.ins().ishl(a, b)
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sqshrn.v") => {
+ let (a, imm32) = match args {
+ [a, imm32] => (a, imm32),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm32 = crate::constant::mir_operand_get_const_val(fx, imm32)
+ .expect("llvm.aarch64.neon.sqshrn.v* imm32 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm32
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm32 not scalar: {:?}", imm32))
+ {
+ imm32 if imm32 < 32 => fx.bcx.ins().sshr_imm(lane, i64::from(imm32 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
+ });
+ }
+
+ _ if intrinsic.starts_with("llvm.aarch64.neon.sqshrun.v") => {
+ let (a, imm32) = match args {
+ [a, imm32] => (a, imm32),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm32 = crate::constant::mir_operand_get_const_val(fx, imm32)
+ .expect("llvm.aarch64.neon.sqshrn.v* imm32 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm32
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm32 not scalar: {:?}", imm32))
+ {
+ imm32 if imm32 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm32 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
+ });
+ }
+ */
+ _ => {
+ fx.tcx.sess.warn(&format!(
+ "unsupported AArch64 llvm intrinsic {}; replacing with trap",
+ intrinsic
+ ));
+ crate::trap::trap_unimplemented(fx, intrinsic);
+ return;
+ }
+ }
+
+ let dest = target.expect("all llvm intrinsics used by stdlib should return");
+ let ret_block = fx.get_block(dest);
+ fx.bcx.ins().jump(ret_block, &[]);
+}
--- /dev/null
+//! Emulate x86 LLVM intrinsics
+
+use crate::intrinsics::*;
+use crate::prelude::*;
+
+use rustc_middle::ty::subst::SubstsRef;
+
+pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ intrinsic: &str,
+ _substs: SubstsRef<'tcx>,
+ args: &[mir::Operand<'tcx>],
+ ret: CPlace<'tcx>,
+ target: Option<BasicBlock>,
+) {
+ match intrinsic {
+ "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
+ // Spin loop hint
+ }
+
+ // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
+ "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
+ intrinsic_args!(fx, args => (a); intrinsic);
+
+ let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_ty = fx.clif_type(lane_ty).unwrap();
+ assert!(lane_count <= 32);
+
+ let mut res = fx.bcx.ins().iconst(types::I32, 0);
+
+ for lane in (0..lane_count).rev() {
+ let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+
+ // 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),
+ _ => a_lane,
+ };
+
+ // extract sign bit of an int
+ let a_lane_sign = fx.bcx.ins().ushr_imm(a_lane, i64::from(lane_ty.bits() - 1));
+
+ // shift sign bit into result
+ let a_lane_sign = clif_intcast(fx, a_lane_sign, types::I32, false);
+ res = fx.bcx.ins().ishl_imm(res, 1);
+ res = fx.bcx.ins().bor(res, a_lane_sign);
+ }
+
+ let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
+ ret.write_cvalue(fx, res);
+ }
+ "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
+ let (x, y, kind) = match args {
+ [x, y, kind] => (x, y, kind),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let x = codegen_operand(fx, x);
+ let y = codegen_operand(fx, y);
+ let kind = crate::constant::mir_operand_get_const_val(fx, kind)
+ .expect("llvm.x86.sse2.cmp.* kind not const");
+
+ let flt_cc = match kind
+ .try_to_bits(Size::from_bytes(1))
+ .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
+ {
+ 0 => FloatCC::Equal,
+ 1 => FloatCC::LessThan,
+ 2 => FloatCC::LessThanOrEqual,
+ 7 => FloatCC::Ordered,
+ 3 => FloatCC::Unordered,
+ 4 => FloatCC::NotEqual,
+ 5 => FloatCC::UnorderedOrGreaterThanOrEqual,
+ 6 => FloatCC::UnorderedOrGreaterThan,
+ kind => unreachable!("kind {:?}", kind),
+ };
+
+ simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
+ let res_lane = match lane_ty.kind() {
+ ty::Float(_) => fx.bcx.ins().fcmp(flt_cc, x_lane, y_lane),
+ _ => unreachable!("{:?}", lane_ty),
+ };
+ bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
+ });
+ }
+ "llvm.x86.sse2.psrli.d" => {
+ let (a, imm8) = match args {
+ [a, imm8] => (a, imm8),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+ .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+ {
+ imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
+ });
+ }
+ "llvm.x86.sse2.pslli.d" => {
+ let (a, imm8) = match args {
+ [a, imm8] => (a, imm8),
+ _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+ };
+ let a = codegen_operand(fx, a);
+ let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+ .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+ simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+ .try_to_bits(Size::from_bytes(4))
+ .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+ {
+ imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
+ _ => fx.bcx.ins().iconst(types::I32, 0),
+ });
+ }
+ "llvm.x86.sse2.storeu.dq" => {
+ intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
+ let mem_addr = mem_addr.load_scalar(fx);
+
+ // FIXME correctly handle the unalignment
+ let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
+ dest.write_cvalue(fx, a);
+ }
+ "llvm.x86.addcarry.64" => {
+ intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
+ let c_in = c_in.load_scalar(fx);
+
+ llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
+ }
+ "llvm.x86.subborrow.64" => {
+ intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
+ let b_in = b_in.load_scalar(fx);
+
+ llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
+ }
+ _ => {
+ fx.tcx.sess.warn(&format!(
+ "unsupported x86 llvm intrinsic {}; replacing with trap",
+ intrinsic
+ ));
+ crate::trap::trap_unimplemented(fx, intrinsic);
+ return;
+ }
+ }
+
+ let dest = target.expect("all llvm intrinsics used by stdlib should return");
+ let ret_block = fx.get_block(dest);
+ fx.bcx.ins().jump(ret_block, &[]);
+}
+
+// llvm.x86.avx2.vperm2i128
+// llvm.x86.ssse3.pshuf.b.128
+// llvm.x86.avx2.pshuf.b
+// llvm.x86.avx2.psrli.w
+// llvm.x86.sse2.psrli.w
+
+fn llvm_add_sub<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ bin_op: BinOp,
+ ret: CPlace<'tcx>,
+ cb_in: Value,
+ a: CValue<'tcx>,
+ b: CValue<'tcx>,
+) {
+ assert_eq!(
+ a.layout().ty,
+ fx.tcx.types.u64,
+ "llvm.x86.addcarry.64/llvm.x86.subborrow.64 second operand must be u64"
+ );
+ assert_eq!(
+ b.layout().ty,
+ fx.tcx.types.u64,
+ "llvm.x86.addcarry.64/llvm.x86.subborrow.64 third operand must be u64"
+ );
+
+ // c + carry -> c + first intermediate carry or borrow respectively
+ let int0 = crate::num::codegen_checked_int_binop(fx, bin_op, a, b);
+ let c = int0.value_field(fx, mir::Field::new(0));
+ let cb0 = int0.value_field(fx, mir::Field::new(1)).load_scalar(fx);
+
+ // c + carry -> c + second intermediate carry or borrow respectively
+ let cb_in_as_u64 = fx.bcx.ins().uextend(types::I64, cb_in);
+ let cb_in_as_u64 = CValue::by_val(cb_in_as_u64, fx.layout_of(fx.tcx.types.u64));
+ let int1 = crate::num::codegen_checked_int_binop(fx, bin_op, c, cb_in_as_u64);
+ let (c, cb1) = int1.load_scalar_pair(fx);
+
+ // carry0 | carry1 -> carry or borrow respectively
+ let cb_out = fx.bcx.ins().bor(cb0, cb1);
+
+ let layout = fx.layout_of(fx.tcx.mk_tup([fx.tcx.types.u8, fx.tcx.types.u64].iter()));
+ let val = CValue::by_val_pair(cb_out, c, layout);
+ ret.write_cvalue(fx, val);
+}
mod cpuid;
mod llvm;
+mod llvm_aarch64;
+mod llvm_x86;
mod simd;
pub(crate) use cpuid::codegen_cpuid_call;
ty => ty,
};
- let val = fx.bcx.ins().bint(int_ty, val);
- let mut res = fx.bcx.ins().ineg(val);
+ let mut res = fx.bcx.ins().bmask(int_ty, val);
if ty.is_float() {
res = fx.bcx.ins().bitcast(ty, res);
ret.write_cvalue(fx, res);
}
sym::bswap => {
- // FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift
- fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
- match bcx.func.dfg.value_type(v) {
- types::I8 => v,
-
- // https://code.woboq.org/gcc/include/bits/byteswap.h.html
- types::I16 => {
- let tmp1 = bcx.ins().ishl_imm(v, 8);
- let n1 = bcx.ins().band_imm(tmp1, 0xFF00);
-
- let tmp2 = bcx.ins().ushr_imm(v, 8);
- let n2 = bcx.ins().band_imm(tmp2, 0x00FF);
-
- bcx.ins().bor(n1, n2)
- }
- types::I32 => {
- let tmp1 = bcx.ins().ishl_imm(v, 24);
- let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000);
-
- let tmp2 = bcx.ins().ishl_imm(v, 8);
- let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000);
-
- let tmp3 = bcx.ins().ushr_imm(v, 8);
- let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00);
-
- let tmp4 = bcx.ins().ushr_imm(v, 24);
- let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF);
-
- let or_tmp1 = bcx.ins().bor(n1, n2);
- let or_tmp2 = bcx.ins().bor(n3, n4);
- bcx.ins().bor(or_tmp1, or_tmp2)
- }
- types::I64 => {
- let tmp1 = bcx.ins().ishl_imm(v, 56);
- let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000_0000_0000u64 as i64);
-
- let tmp2 = bcx.ins().ishl_imm(v, 40);
- let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000_0000_0000u64 as i64);
-
- let tmp3 = bcx.ins().ishl_imm(v, 24);
- let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00_0000_0000u64 as i64);
-
- let tmp4 = bcx.ins().ishl_imm(v, 8);
- let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF_0000_0000u64 as i64);
-
- let tmp5 = bcx.ins().ushr_imm(v, 8);
- let n5 = bcx.ins().band_imm(tmp5, 0x0000_0000_FF00_0000u64 as i64);
-
- let tmp6 = bcx.ins().ushr_imm(v, 24);
- let n6 = bcx.ins().band_imm(tmp6, 0x0000_0000_00FF_0000u64 as i64);
-
- let tmp7 = bcx.ins().ushr_imm(v, 40);
- let n7 = bcx.ins().band_imm(tmp7, 0x0000_0000_0000_FF00u64 as i64);
-
- let tmp8 = bcx.ins().ushr_imm(v, 56);
- let n8 = bcx.ins().band_imm(tmp8, 0x0000_0000_0000_00FFu64 as i64);
-
- let or_tmp1 = bcx.ins().bor(n1, n2);
- let or_tmp2 = bcx.ins().bor(n3, n4);
- let or_tmp3 = bcx.ins().bor(n5, n6);
- let or_tmp4 = bcx.ins().bor(n7, n8);
-
- let or_tmp5 = bcx.ins().bor(or_tmp1, or_tmp2);
- let or_tmp6 = bcx.ins().bor(or_tmp3, or_tmp4);
- bcx.ins().bor(or_tmp5, or_tmp6)
- }
- types::I128 => {
- let (lo, hi) = bcx.ins().isplit(v);
- let lo = swap(bcx, lo);
- let hi = swap(bcx, hi);
- bcx.ins().iconcat(hi, lo)
- }
- ty => unreachable!("bswap {}", ty),
- }
- }
intrinsic_args!(fx, args => (arg); intrinsic);
let val = arg.load_scalar(fx);
- let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout());
+ let res = if fx.bcx.func.dfg.value_type(val) == types::I8 {
+ val
+ } else {
+ fx.bcx.ins().bswap(val)
+ };
+ let res = CValue::by_val(res, arg.layout());
ret.write_cvalue(fx, res);
}
sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new);
let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old);
- let ret_val =
- CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
+ let ret_val = CValue::by_val_pair(old, is_eq, ret.layout());
ret.write_cvalue(fx, ret_val)
}
flags.set_notrap();
let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
- let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
- fx.bcx.ins().bint(types::I8, eq)
+ fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val)
} else {
// Just call `memcmp` (like slices do in core) when the
// size is too large or it's not a power-of-two.
let returns = vec![AbiParam::new(types::I32)];
let args = &[lhs_ref, rhs_ref, bytes_val];
let cmp = fx.lib_call("memcmp", params, returns, args)[0];
- let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
- fx.bcx.ins().bint(types::I8, eq)
+ fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0)
};
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
}
_ => unreachable!(),
};
- let ty = fx.clif_type(res_lane_ty).unwrap();
-
- let res_lane = fx.bcx.ins().bint(ty, res_lane);
- fx.bcx.ins().ineg(res_lane)
+ bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
});
}
let res_type =
Type::int_with_byte_size(u16::try_from(expected_bytes).unwrap()).unwrap();
- let mut res = fx.bcx.ins().iconst(res_type, 0);
+ let mut res = type_zero_value(&mut fx.bcx, res_type);
let lanes = match fx.tcx.sess.target.endian {
Endian::Big => Box::new(0..lane_count) as Box<dyn Iterator<Item = u64>>,
returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
call_conv: crate::conv_to_call_conv(
tcx.sess.target.options.entry_abi,
- CallConv::triple_default(m.isa().triple()),
+ m.target_config().default_call_conv,
),
};
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
let main_name = tcx.symbol_name(instance).name;
- let main_sig = get_function_sig(tcx, m.isa().triple(), instance);
+ let main_sig = get_function_sig(tcx, m.target_config().default_call_conv, instance);
let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
let mut ctx = Context::new();
.polymorphize(tcx);
let report_name = tcx.symbol_name(report).name;
- let report_sig = get_function_sig(tcx, m.isa().triple(), report);
+ let report_sig = get_function_sig(tcx, m.target_config().default_call_conv, report);
let report_func_id =
m.declare_function(report_name, Linkage::Import, &report_sig).unwrap();
let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func);
) -> CValue<'tcx> {
let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
- let val = fx.bcx.ins().bint(types::I8, val);
CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
}
_ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs),
};
- let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
-
let out_layout = fx.layout_of(fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()));
CValue::by_val_pair(res, has_overflow, out_layout)
}
_ => unreachable!(),
};
let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
- let val = fx.bcx.ins().bint(types::I8, val);
return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
}
_ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
_ => panic!("bin_op {:?} on ptr", bin_op),
};
- CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool))
+ CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
}
}
use cranelift_codegen::ir::{condcodes::IntCC, InstructionData, Opcode, Value, ValueDef};
use cranelift_frontend::FunctionBuilder;
-/// If the given value was produced by a `bint` instruction, return it's input, otherwise return the
-/// given value.
-pub(crate) fn maybe_unwrap_bint(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value {
- if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
- match bcx.func.dfg[arg_inst] {
- InstructionData::Unary { opcode: Opcode::Bint, arg } => arg,
- _ => arg,
- }
- } else {
- arg
- }
-}
-
/// If the given value was produced by the lowering of `Rvalue::Not` return the input and true,
/// otherwise return the given value and false.
pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) {
};
match bcx.func.dfg[arg_inst] {
- InstructionData::UnaryBool { opcode: Opcode::Bconst, imm } => {
- if test_zero {
- Some(!imm)
- } else {
- Some(imm)
- }
- }
InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
if test_zero {
Some(imm.bits() == 0)
local: Local,
layout: TyAndLayout<'tcx>,
) -> CPlace<'tcx> {
- let var = Variable::with_u32(fx.next_ssa_var);
+ let var = Variable::from_u32(fx.next_ssa_var);
fx.next_ssa_var += 1;
fx.bcx.declare_var(var, fx.clif_type(layout.ty).unwrap());
CPlace { inner: CPlaceInner::Var(local, var), layout }
local: Local,
layout: TyAndLayout<'tcx>,
) -> CPlace<'tcx> {
- let var1 = Variable::with_u32(fx.next_ssa_var);
+ let var1 = Variable::from_u32(fx.next_ssa_var);
fx.next_ssa_var += 1;
- let var2 = Variable::with_u32(fx.next_ssa_var);
+ let var2 = Variable::from_u32(fx.next_ssa_var);
fx.next_ssa_var += 1;
let (ty1, ty2) = fx.clif_pair_type(layout.ty).unwrap();
| (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().raw_bitcast(dst_ty, data)
- }
+ _ if src_ty.is_vector() && dst_ty.is_vector() => fx.bcx.ins().bitcast(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 {
return;
}
CPlaceInner::VarPair(_local, var1, var2) => {
- let (data1, data2) = CValue(from.0, dst_layout).load_scalar_pair(fx);
+ let (ptr, meta) = from.force_stack(fx);
+ assert!(meta.is_none());
+ let (data1, data2) =
+ CValue(CValueInner::ByRef(ptr, None), dst_layout).load_scalar_pair(fx);
let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap();
transmute_value(fx, var1, data1, dst_ty1);
transmute_value(fx, var2, data2, dst_ty2);
#!/usr/bin/env bash
-exec ./y.rs test
+exec ./y.rs test "$@"
# This block is ignored by rustc
set -e
echo "[BUILD] y.rs" 1>&2
-rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1
+rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021
exec ${0/.rs/.bin} $@
*/
match (src.layout.abi, dst.layout.abi) {
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
- if (src_scalar.primitive() == abi::Pointer)
- == (dst_scalar.primitive() == abi::Pointer)
- {
+ let src_is_ptr = src_scalar.primitive() == abi::Pointer;
+ let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
+ if src_is_ptr == dst_is_ptr {
assert_eq!(src.layout.size, dst.layout.size);
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
// conversions allow handling `bool`s the same as `u8`s.
let src = bx.from_immediate(src.immediate());
- let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
+ // LLVM also doesn't like `bitcast`s between pointers in different address spaces.
+ let src_as_dst = if src_is_ptr {
+ bx.pointercast(src, bx.backend_type(dst.layout))
+ } else {
+ bx.bitcast(src, bx.backend_type(dst.layout))
+ };
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
return;
}
};
let kind = match parent_ty.ty.kind() {
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind()
}
kind => kind,
// Types with identity (print the module path).
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
| ty::FnDef(def_id, substs)
- | ty::Alias(_, ty::AliasTy { def_id, substs })
+ | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
/// Iterate over the keys, sorted
#[inline]
pub fn keys(&self) -> impl Iterator<Item = &K> + ExactSizeIterator + DoubleEndedIterator {
- self.data.iter().map(|&(ref k, _)| k)
+ self.data.iter().map(|(k, _)| k)
}
/// Iterate over values, sorted by key
#[inline]
pub fn values(&self) -> impl Iterator<Item = &V> + ExactSizeIterator + DoubleEndedIterator {
- self.data.iter().map(|&(_, ref v)| v)
+ self.data.iter().map(|(_, v)| v)
}
#[inline]
K: Borrow<Q>,
Q: Ord + ?Sized,
{
- self.data.binary_search_by(|&(ref x, _)| x.borrow().cmp(key))
+ self.data.binary_search_by(|(x, _)| x.borrow().cmp(key))
}
#[inline]
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let mut data: Vec<(K, V)> = iter.into_iter().collect();
- data.sort_unstable_by(|&(ref k1, _), &(ref k2, _)| k1.cmp(k2));
+ data.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));
data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| k1.cmp(k2) == Ordering::Equal);
SortedMap { data }
.where_label = this `where` clause might not match the one in the trait
.bounds_label = this bound might be missing in the impl
+hir_analysis_async_trait_impl_should_be_async =
+ method `{$method_name}` should be async because the method from the trait is async
+ .trait_item_label = required because the trait method is async
+
hir_analysis_drop_impl_on_wrong_item =
the `Drop` trait may only be implemented for local structs, enums, and unions
.label = must be a struct, enum, or union in the current crate
}
// Find overlapping multiline annotations, put them at different depths
- multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, usize::MAX - ml.line_end));
+ multiline_annotations.sort_by_key(|(_, ml)| (ml.line_start, usize::MAX - ml.line_end));
for (_, ann) in multiline_annotations.clone() {
for (_, a) in multiline_annotations.iter_mut() {
// Move all other multiline annotations overlapping with this one
// Account for the difference between the width of the current code and the
// snippet being suggested, so that the *later* suggestions are correctly
// aligned on the screen.
- acc += len as isize - (cur_hi.col.0 - cur_lo.col.0) as isize;
+ acc += len - (cur_hi.col.0 - cur_lo.col.0) as isize;
}
prev_hi = cur_hi;
prev_line = sf.get_line(prev_hi.line - 1);
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
let poly_trait_ref =
- ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
+ ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
debug!(?poly_trait_ref, ?assoc_bindings);
bounds.trait_bounds.push((poly_trait_ref, span, constness));
if let Some(b) = trait_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
- ty::TraitRef::new(trait_def_id, substs)
+ self.tcx().mk_trait_ref(trait_def_id, substs)
}
#[instrument(level = "debug", skip(self, span))]
debug!(?substs_trait_ref_and_assoc_item);
- ty::AliasTy { def_id: assoc_item.def_id, substs: substs_trait_ref_and_assoc_item }
+ self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
});
if !speculative {
assoc_item,
assoc_item,
default.span,
- ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs },
+ tcx.mk_trait_ref(it.owner_id.to_def_id(), trait_substs),
);
}
_ => {}
impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, substs: _ }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
self.0.push(def);
ControlFlow::CONTINUE
}
return;
}
+ if let Err(_) = compare_asyncness(tcx, impl_m, impl_m_span, trait_m, trait_item_span) {
+ return;
+ }
+
if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
{
return;
Ok(())
}
+fn compare_asyncness<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ impl_m: &ty::AssocItem,
+ impl_m_span: Span,
+ trait_m: &ty::AssocItem,
+ trait_item_span: Option<Span>,
+) -> Result<(), ErrorGuaranteed> {
+ if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
+ match tcx.fn_sig(impl_m.def_id).skip_binder().output().kind() {
+ ty::Alias(ty::Opaque, ..) => {
+ // allow both `async fn foo()` and `fn foo() -> impl Future`
+ }
+ ty::Error(rustc_errors::ErrorGuaranteed { .. }) => {
+ // We don't know if it's ok, but at least it's already an error.
+ }
+ _ => {
+ return Err(tcx.sess.emit_err(crate::errors::AsyncTraitImplShouldBeAsync {
+ span: impl_m_span,
+ method_name: trait_m.name,
+ trait_item_span,
+ }));
+ }
+ };
+ }
+
+ Ok(())
+}
+
#[instrument(skip(tcx), level = "debug", ret)]
pub fn collect_trait_impl_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
_ => predicates.push(
ty::Binder::bind_with_vars(
ty::ProjectionPredicate {
- projection_ty: ty::AliasTy {
- def_id: trait_ty.def_id,
- substs: rebased_substs,
- },
+ projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_substs),
term: impl_ty_value.into(),
},
bound_vars,
pub ident: Ident,
}
+#[derive(Diagnostic)]
+#[diag(hir_analysis_async_trait_impl_should_be_async)]
+pub struct AsyncTraitImplShouldBeAsync {
+ #[primary_span]
+ // #[label]
+ pub span: Span,
+ #[label(trait_item_label)]
+ pub trait_item_span: Option<Span>,
+ pub method_name: Symbol,
+}
+
#[derive(Diagnostic)]
#[diag(hir_analysis_drop_impl_on_wrong_item, code = "E0120")]
pub struct DropImplOnWrongItem {
#[instrument(level = "trace", skip(self), ret)]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
- ty::Alias(_, ty::AliasTy { def_id, substs })
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
if matches!(
self.tcx.def_kind(*def_id),
DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
// instead of requiring an additional `+ 'a`.
match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
- trait_ref: ty::TraitRef { def_id: _, substs },
+ trait_ref: ty::TraitRef { def_id: _, substs, .. },
constness: _,
polarity: _,
})) => {
}
}
ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate {
- projection_ty: ty::AliasTy { substs, def_id: _ },
+ projection_ty: ty::AliasTy { substs, .. },
term,
})) => {
for subst in &substs[1..] {
self.print_qpath(qpath, true);
self.popen();
if let Some(ddpos) = ddpos.as_opt_usize() {
- let ddpos = ddpos as usize;
self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
if ddpos != 0 {
self.word_space(",");
let substs = sig.output().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) = *ty.kind()
+ && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind()
&& def_id == rpit_def_id
{
Some(substs)
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
assert_eq!(trait_pred.trait_ref.self_ty(), opaque_ty);
ty::PredicateKind::Clause(ty::Clause::Trait(
- trait_pred.with_self_type(self.tcx, ty),
+ trait_pred.with_self_ty(self.tcx, ty),
))
}
ty::PredicateKind::Clause(ty::Clause::Projection(mut proj_pred)) => {
assert_eq!(proj_pred.projection_ty.self_ty(), opaque_ty);
- proj_pred.projection_ty.substs = self.tcx.mk_substs_trait(
- ty,
- proj_pred.projection_ty.substs.iter().skip(1),
- );
+ proj_pred = proj_pred.with_self_ty(self.tcx, ty);
ty::PredicateKind::Clause(ty::Clause::Projection(proj_pred))
}
_ => continue,
expected_ty: Ty<'tcx>,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
match *expected_ty.kind() {
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => self
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
.deduce_signature_from_predicates(
self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
),
get_future_output(obligation.predicate, obligation.cause.span)
})?
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => self
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
.tcx
.bound_explicit_item_bounds(def_id)
.subst_iter_copied(self.tcx, substs)
{
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
// Get the `impl Trait`'s `DefId`.
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = ty.kind()
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind()
// Get the `impl Trait`'s `Item` so that we can get its trait bounds and
// get the `Trait`'s `DefId`.
&& let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
ty::Param(param_ty) => {
self.point_at_param_definition(&mut err, param_ty);
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: _, substs: _ }) => {
+ ty::Alias(ty::Opaque, _) => {
self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs());
}
_ => {}
if formal_ret.has_infer_types() {
for ty in ret_ty.walk() {
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
- && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *ty.kind()
+ && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
&& let Some(def_id) = def_id.as_local()
&& self.opaque_type_origin(def_id, DUMMY_SP).is_some() {
return None;
}
}
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, substs: _ })
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, .. })
| ty::Closure(new_def_id, _)
| ty::FnDef(new_def_id, _) => {
def_id = new_def_id;
_ => {
// Look for a user-provided impl of a `Fn` trait, and point to it.
let new_def_id = self.probe(|_| {
- let trait_ref = ty::TraitRef::new(
+ let trait_ref = self.tcx.mk_trait_ref(
call_kind.to_def_id(self.tcx),
- self.tcx.mk_substs(
- [
- ty::GenericArg::from(callee_ty),
- self.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: rustc_span::DUMMY_SP,
- })
- .into(),
- ]
- .into_iter(),
- ),
+ [
+ callee_ty,
+ self.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: rustc_span::DUMMY_SP,
+ }),
+ ],
);
let obligation = traits::Obligation::new(
self.tcx,
use rustc_infer::infer;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty};
+use rustc_middle::ty::{self, Binder, DefIdTree, IsSuggestable, Ty};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::symbol::sym;
use rustc_span::Span;
let fn_sig = substs.as_closure().sig();
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
// Check that we're in fact trying to clone into the expected type
&& self.can_coerce(*pointee_ty, expected_ty)
// And the expected type doesn't implement `Clone`
- && !self.predicate_must_hold_considering_regions(&traits::Obligation {
- cause: traits::ObligationCause::dummy(),
- param_env: self.param_env,
- recursion_depth: 0,
- predicate: ty::Binder::dummy(ty::TraitRef {
- def_id: clone_trait_did,
- substs: self.tcx.mk_substs([expected_ty.into()].iter()),
- })
- .without_const()
- .to_predicate(self.tcx),
- })
+ && !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
+ self.tcx,
+ traits::ObligationCause::dummy(),
+ self.param_env,
+ ty::Binder::dummy(self.tcx.mk_trait_ref(
+ clone_trait_did,
+ [expected_ty],
+ )),
+ ))
{
diag.span_note(
callee_expr.span,
}
ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did(), hir_id, data),
// FIXME: support adding the attribute to TAITs
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, substs: _ }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
let mut has_emitted = false;
for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
// We only look at the `DefId`, so it is safe to skip the binder here.
self.var_for_def(span, param)
});
- let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+ let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
self.var_for_def(span, param)
});
- let trait_ref = ty::TraitRef::new(trait_def_id, substs);
+ let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
let trait_substs = self.fresh_item_substs(trait_def_id);
- let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+ let trait_ref = self.tcx.mk_trait_ref(trait_def_id, trait_substs);
if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, assume all supertraits are relevant.
.chain(projection_ty.substs.iter().skip(1)),
);
- let quiet_projection_ty = ty::AliasTy {
- substs: substs_with_infer_self,
- def_id: projection_ty.def_id,
- };
+ let quiet_projection_ty =
+ tcx.mk_alias_ty(projection_ty.def_id, substs_with_infer_self);
let term = pred.skip_binder().term;
}
}
} else {
- err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+ let ty_str = if ty_str.len() > 50 {
+ String::new()
+ } else {
+ format!("on `{ty_str}` ")
+ };
+ err.span_label(span, format!(
+ "{item_kind} cannot be called {ty_str}due to unsatisfied trait bounds"
+ ));
}
};
impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
type BreakTy = ();
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *t.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *t.kind() {
if def_id == self.def_id.to_def_id() {
return ControlFlow::Break(());
}
// relatable.
Ok(t)
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
let s = self.relate(substs, substs)?;
Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
}
}
(
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: _ }),
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
}
- (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }), _)
- | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }))
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types && def_id.is_local() =>
{
self.fields.obligations.extend(
impl<'tcx> InferCtxt<'tcx> {
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
let (def_id, substs) = match *ty.kind() {
- ty::Alias(_, ty::AliasTy { def_id, substs })
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
if matches!(
self.tcx.def_kind(def_id),
DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
match *ty.kind() {
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => {
- Some((Self::Opaque, def_id))
- }
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => Some((Self::Opaque, def_id)),
ty::Generator(def_id, ..) => {
Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
}
false
};
- let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
- def_id: trait_def_id,
- substs: expected_substs,
- });
- let actual_trait_ref = self
+ let expected_trait_ref = self
.cx
- .resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
+ .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs));
+ let actual_trait_ref =
+ self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs));
// Search the expected and actual trait references to see (a)
// whether the sub/sup placeholders appear in them (sometimes
StatementAsExpression::CorrectType
}
(
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: _ }),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: _ }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, .. }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, .. }),
) if last_def_id == exp_def_id => StatementAsExpression::CorrectType,
(
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: last_bounds }),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: exp_bounds }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: last_def_id, substs: last_bounds, .. }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: exp_def_id, substs: exp_bounds, .. }),
) => {
debug!(
"both opaque, likely future {:?} {:?} {:?} {:?}",
}
(
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: _ }),
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
- (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }), _)
- | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }))
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if this.define_opaque_types() && def_id.is_local() =>
{
this.add_obligations(
(&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
(
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: _ }),
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| {
self.tcx().sess.delay_span_bug(
self.delegate.span(),
);
if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
}),
- (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }), _)
- | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }))
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if def_id.is_local() =>
{
self.relate_opaques(a, b)
lt_op: |lt| lt,
ct_op: |ct| ct,
ty_op: |ty| match *ty.kind() {
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ })
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
if replace_opaque_type(def_id) =>
{
let def_span = self.tcx.def_span(def_id);
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) if def_id.is_local() => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) if def_id.is_local() => {
let def_id = def_id.expect_local();
let origin = match self.defining_use_anchor {
DefiningAnchor::Bind(_) => {
DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
DefiningAnchor::Error => return None,
};
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }) =
- *b.kind()
- {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
// We could accept this, but there are various ways to handle this situation, and we don't
// want to make a decision on it right now. Likely this case is so super rare anyway, that
// no one encounters it in practice.
substs.as_generator().resume_ty().visit_with(self);
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref substs, .. }) => {
// Skip lifetime paramters that are not captures.
let variances = self.tcx.variances_of(*def_id);
}
// Replace all other mentions of the same opaque type with the hidden type,
// as the bounds must hold on the hidden type after all.
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2 })
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, substs: substs2, .. })
if def_id.to_def_id() == def_id2 && substs == substs2 =>
{
hidden_ty
}
// FIXME(RPITIT): This can go away when we move to associated types
- ty::Alias(ty::Projection, ty::AliasTy { def_id: def_id2, substs: substs2 })
- if def_id.to_def_id() == def_id2 && substs == substs2 =>
- {
- hidden_ty
- }
+ ty::Alias(
+ ty::Projection,
+ ty::AliasTy { def_id: def_id2, substs: substs2, .. },
+ ) if def_id.to_def_id() == def_id2 && substs == substs2 => hidden_ty,
_ => ty,
},
lt_op: |lt| lt,
// outlives any other lifetime, which is unsound.
// See https://github.com/rust-lang/rust/issues/84305 for
// more details.
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
out.push(Component::Opaque(def_id, substs));
},
substs,
true,
|ty| match *ty.kind() {
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => (def_id, substs),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
_ => bug!("expected only projection types from env, not {:?}", ty),
},
);
}
(
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: _ }),
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: _ }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => {
self.fields.infcx.super_combine_tys(self, a, b)?;
Ok(a)
}
- (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }), _)
- | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }))
+ (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
+ | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types && def_id.is_local() =>
{
self.fields.obligations.extend(
tcx.associated_items(trait_id)
.find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
.and_then(|assoc| {
- let proj = tcx.mk_projection(assoc.def_id, tcx.mk_substs_trait(self_ty, []));
+ let proj = tcx.mk_projection(assoc.def_id, [self_ty]);
tcx.try_normalize_erasing_regions(self.param_env, proj).ok()
})
}
// then we can emit a suggestion to add the bound.
let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) {
(
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)),
) => Some(AddBound {
suggest_span: cx.tcx.def_span(*def_id).shrink_to_hi(),
if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
&& let ty = cx.typeck_results().expr_ty(&await_expr)
- && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, substs: _ }) = ty.kind()
+ && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind()
&& cx.tcx.ty_is_opaque_future(ty)
// FIXME: This also includes non-async fns that return `impl Future`.
&& let async_fn_def_id = cx.tcx.parent(*future_def_id)
.map(|inner| MustUsePath::Boxed(Box::new(inner)))
}
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, substs: _ }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
elaborate_predicates_with_span(
cx.tcx,
cx.tcx.explicit_item_bounds(def).iter().cloned(),
let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?;
// If we're not in a "rustc_" crate, bail.
- let Some(("rustc", slug_prefix)) = crate_name.split_once("_") else { return None };
+ let Some(("rustc", slug_prefix)) = crate_name.split_once('_') else { return None };
let slug_name = slug.segments.first()?.ident.to_string();
if !slug_name.starts_with(slug_prefix) {
pub fn function_handle(
tcx: TyCtxt<'tcx>,
def_id: DefId,
- substs: SubstsRef<'tcx>,
+ substs: impl IntoIterator<Item = GenericArg<'tcx>>,
span: Span,
) -> Self {
let ty = tcx.mk_fn_def(def_id, substs);
.find(|m| m.kind == ty::AssocKind::Fn)
.unwrap()
.def_id;
- tcx.mk_fn_def(method_def_id, tcx.mk_substs_trait(source, []))
+ tcx.mk_fn_def(method_def_id, [source])
}
}
use crate::traits;
use crate::ty::query::{self, TyCtxtAt};
use crate::ty::{
- self, AdtDef, AdtDefData, AdtKind, AliasTy, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
+ self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
ClosureSizeProfileData, Const, ConstS, DefIdTree, FloatTy, FloatVar, FloatVid,
GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions,
/// Given a `ty`, return whether it's an `impl Future<...>`.
pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
- let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = ty.kind() else { return false };
+ let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
let future_trait = self.require_lang_item(LangItem::Future, None);
self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
}
#[inline]
- pub fn mk_fn_def(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
- debug_assert_eq!(
- self.generics_of(def_id).count(),
- substs.len(),
- "wrong number of generic parameters for {def_id:?}: {substs:?}",
- );
+ pub fn mk_fn_def(
+ self,
+ def_id: DefId,
+ substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ ) -> Ty<'tcx> {
+ let substs = self.check_substs(def_id, substs);
self.mk_ty(FnDef(def_id, substs))
}
+ #[inline(always)]
+ fn check_substs(
+ self,
+ _def_id: DefId,
+ substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ ) -> SubstsRef<'tcx> {
+ let substs = substs.into_iter().map(Into::into);
+ #[cfg(debug_assertions)]
+ {
+ let n = self.generics_of(_def_id).count();
+ assert_eq!(
+ (n, Some(n)),
+ substs.size_hint(),
+ "wrong number of generic parameters for {_def_id:?}: {:?}",
+ substs.collect::<Vec<_>>(),
+ );
+ }
+ self.mk_substs(substs)
+ }
+
#[inline]
pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
self.mk_ty(FnPtr(fty))
}
#[inline]
- pub fn mk_projection(self, item_def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
- debug_assert_eq!(
- self.generics_of(item_def_id).count(),
- substs.len(),
- "wrong number of generic parameters for {item_def_id:?}: {substs:?}",
- );
- self.mk_ty(Alias(ty::Projection, AliasTy { def_id: item_def_id, substs }))
+ pub fn mk_projection(
+ self,
+ item_def_id: DefId,
+ substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ ) -> Ty<'tcx> {
+ self.mk_ty(Alias(ty::Projection, self.mk_alias_ty(item_def_id, substs)))
}
#[inline]
#[inline]
pub fn mk_opaque(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
- self.mk_ty(Alias(ty::Opaque, ty::AliasTy { def_id, substs }))
+ self.mk_ty(Alias(ty::Opaque, self.mk_alias_ty(def_id, substs)))
}
pub fn mk_place_field(self, place: Place<'tcx>, f: Field, ty: Ty<'tcx>) -> Place<'tcx> {
trait_def_id: DefId,
substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
) -> ty::TraitRef<'tcx> {
- let substs = substs.into_iter().map(Into::into);
- let n = self.generics_of(trait_def_id).count();
- debug_assert_eq!(
- (n, Some(n)),
- substs.size_hint(),
- "wrong number of generic parameters for {trait_def_id:?}: {:?} \nDid you accidentally include the self-type in the params list?",
- substs.collect::<Vec<_>>(),
- );
- let substs = self.mk_substs(substs);
- ty::TraitRef::new(trait_def_id, substs)
+ let substs = self.check_substs(trait_def_id, substs);
+ ty::TraitRef { def_id: trait_def_id, substs, _use_mk_trait_ref_instead: () }
+ }
+
+ pub fn mk_alias_ty(
+ self,
+ def_id: DefId,
+ substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
+ ) -> ty::AliasTy<'tcx> {
+ let substs = self.check_substs(def_id, substs);
+ ty::AliasTy { def_id, substs, _use_mk_alias_ty_instead: () }
}
pub fn mk_bound_variable_kinds<
use std::ops::ControlFlow;
use crate::ty::{
- visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst,
- InferTy, Opaque, PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
+ visit::TypeVisitable, AliasTy, Const, ConstKind, DefIdTree, InferConst, InferTy, Opaque,
+ PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
};
use rustc_data_structures::fx::FxHashMap;
return ControlFlow::Break(());
}
- Alias(Opaque, AliasTy { def_id, substs: _ }) => {
+ Alias(Opaque, AliasTy { def_id, .. }) => {
let parent = self.tcx.parent(*def_id);
if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent)
- && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, substs: _ }) = self.tcx.type_of(parent).kind()
+ && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = self.tcx.type_of(parent).kind()
&& parent_opaque_def_id == def_id
{
// Okay
}
}
- Dynamic(dty, _, _) => {
- for pred in *dty {
- match pred.skip_binder() {
- ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => {
- // Okay
- }
- _ => return ControlFlow::Break(()),
- }
- }
- }
-
Param(param) => {
// FIXME: It would be nice to make this not use string manipulation,
// but it's pretty hard to do this, since `ty::ParamTy` is missing
ty: Ty<'tcx>,
) -> bool {
let assoc = self.associated_item(proj_ty.def_id);
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *proj_ty.self_ty().kind()
- {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
let opaque_local_def_id = def_id.as_local();
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
match &self.hir().expect_item(opaque_local_def_id).kind {
self.add_projection_ty(data);
}
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: _, substs }) => {
+ &ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => {
self.add_flags(TypeFlags::HAS_TY_OPAQUE);
self.add_substs(substs);
}
}
}
- pub fn with_self_type(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
- Self { trait_ref: self.trait_ref.with_self_type(tcx, self_ty), ..self }
+ pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+ Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self }
}
pub fn def_id(self) -> DefId {
}
}
+impl<'tcx> ProjectionPredicate<'tcx> {
+ pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+ Self {
+ projection_ty: tcx.mk_alias_ty(
+ self.projection_ty.def_id,
+ [self_ty.into()].into_iter().chain(self.projection_ty.substs.iter().skip(1)),
+ ),
+ ..self
+ }
+ }
+}
+
pub trait ToPolyTraitRef<'tcx> {
fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
}
self.path_append(
|cx: Self| {
if trait_qualify_parent {
- let trait_ref = ty::TraitRef::new(
- parent_def_id,
- cx.tcx().intern_substs(parent_substs),
- );
+ let trait_ref =
+ cx.tcx().mk_trait_ref(parent_def_id, parent_substs.iter().copied());
cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
} else {
cx.print_def_path(parent_def_id, parent_substs)
}
}
ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
// FIXME(eddyb) print this with `print_def_path`.
// We use verbose printing in 'NO_QUERIES' mode, to
// avoid needing to call `predicates_of`. This should
let parent = self.tcx().parent(def_id);
match self.tcx().def_kind(parent) {
DefKind::TyAlias | DefKind::AssocTy => {
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, substs: _ }) =
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: d, .. }) =
*self.tcx().type_of(parent).kind()
{
if d == def_id {
Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id)))
} else {
let substs = relation.relate(a.substs, b.substs)?;
- Ok(ty::AliasTy { def_id: a.def_id, substs: &substs })
+ Ok(relation.tcx().mk_alias_ty(a.def_id, substs))
}
}
}
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
let substs = relate_substs(relation, a.substs, b.substs)?;
- Ok(ty::TraitRef { def_id: a.def_id, substs })
+ Ok(relation.tcx().mk_trait_ref(a.def_id, substs))
}
}
}
}
(
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs }),
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
) if a_def_id == b_def_id => {
if relation.intercrate() {
// During coherence, opaque types should be treated as equal to each other, even if their generic params
pub struct TraitRef<'tcx> {
pub def_id: DefId,
pub substs: SubstsRef<'tcx>,
+ /// This field exists to prevent the creation of `TraitRef` without
+ /// calling [TyCtxt::mk_trait_ref].
+ pub(super) _use_mk_trait_ref_instead: (),
}
impl<'tcx> TraitRef<'tcx> {
- pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> TraitRef<'tcx> {
- TraitRef { def_id, substs }
- }
-
- pub fn with_self_type(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+ pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
tcx.mk_trait_ref(
self.def_id,
[self_ty.into()].into_iter().chain(self.substs.iter().skip(1)),
/// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
/// are the parameters defined on trait.
pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> {
- ty::Binder::dummy(TraitRef {
- def_id,
- substs: InternalSubsts::identity_for_item(tcx, def_id),
- })
+ ty::Binder::dummy(tcx.mk_trait_ref(def_id, InternalSubsts::identity_for_item(tcx, def_id)))
}
#[inline]
substs: SubstsRef<'tcx>,
) -> ty::TraitRef<'tcx> {
let defs = tcx.generics_of(trait_id);
- ty::TraitRef { def_id: trait_id, substs: tcx.intern_substs(&substs[..defs.params.len()]) }
+ tcx.mk_trait_ref(trait_id, tcx.intern_substs(&substs[..defs.params.len()]))
}
}
/// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
/// aka. `tcx.parent(def_id)`.
pub def_id: DefId,
+
+ /// This field exists to prevent the creation of `ProjectionTy` without using
+ /// [TyCtxt::mk_alias_ty].
+ pub(super) _use_mk_alias_ty_instead: (),
}
impl<'tcx> AliasTy<'tcx> {
let trait_def_id = self.trait_def_id(tcx);
let trait_generics = tcx.generics_of(trait_def_id);
(
- ty::TraitRef {
- def_id: trait_def_id,
- substs: self.substs.truncate_to(tcx, trait_generics),
- },
+ tcx.mk_trait_ref(trait_def_id, self.substs.truncate_to(tcx, trait_generics)),
&self.substs[trait_generics.count()..],
)
}
/// as well.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
let def_id = self.trait_def_id(tcx);
- ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
+ tcx.mk_trait_ref(def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
}
pub fn self_ty(&self) -> Ty<'tcx> {
debug_assert!(!self_ty.has_escaping_bound_vars());
ty::ProjectionPredicate {
- projection_ty: ty::AliasTy {
- def_id: self.def_id,
- substs: tcx.mk_substs_trait(self_ty, self.substs),
- },
+ projection_ty: tcx
+ .mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs)),
term: self.term,
}
}
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) = *t.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *t.kind() {
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
} else if t.has_opaque_types() {
t.super_fold_with(self)
let exchange_malloc = Operand::function_handle(
tcx,
tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)),
- ty::List::empty(),
+ [],
expr_span,
);
let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span);
method_name: Symbol,
substs: impl IntoIterator<Item = impl Into<GenericArg<'tcx>>>,
) -> ConstantKind<'tcx> {
- let substs = tcx.mk_substs(substs.into_iter().map(Into::into));
-
// The unhygienic comparison here is acceptable because this is only
// used on known traits.
let item = tcx
let drop_trait = tcx.require_lang_item(LangItem::Drop, None);
let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
let ty = self.place_ty(self.place);
- let substs = tcx.mk_substs_trait(ty, []);
let ref_ty =
tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut });
)],
terminator: Some(Terminator {
kind: TerminatorKind::Call {
- func: Operand::function_handle(tcx, drop_fn, substs, self.source_info.span),
+ func: Operand::function_handle(
+ tcx,
+ drop_fn,
+ [ty.into()],
+ self.source_info.span,
+ ),
args: vec![Operand::Move(Place::from(ref_place))],
destination: unit_temp,
target: Some(succ),
use crate::MirPass;
use rustc_data_structures::fx::FxHashMap;
use rustc_index::bit_set::BitSet;
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::{dump_mir, PassWhere};
use rustc_middle::mir::{
traversal, BasicBlock, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place,
Rvalue, Statement, StatementKind, TerminatorKind,
};
-use rustc_middle::mir::{
- visit::{MutVisitor, PlaceContext, Visitor},
- ProjectionElem,
-};
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::impls::MaybeLiveLocals;
use rustc_mir_dataflow::{Analysis, ResultsCursor};
// through these methods, and not directly.
impl<'alloc> Candidates<'alloc> {
/// Just `Vec::retain`, but the condition is inverted and we add debugging output
- fn vec_remove_debug(
+ fn vec_filter_candidates(
src: Local,
v: &mut Vec<Local>,
- mut f: impl FnMut(Local) -> bool,
+ mut f: impl FnMut(Local) -> CandidateFilter,
at: Location,
) {
v.retain(|dest| {
let remove = f(*dest);
- if remove {
+ if remove == CandidateFilter::Remove {
trace!("eliminating {:?} => {:?} due to conflict at {:?}", src, dest, at);
}
- !remove
+ remove == CandidateFilter::Keep
});
}
- /// `vec_remove_debug` but for an `Entry`
- fn entry_remove(
+ /// `vec_filter_candidates` but for an `Entry`
+ fn entry_filter_candidates(
mut entry: OccupiedEntry<'_, Local, Vec<Local>>,
p: Local,
- f: impl FnMut(Local) -> bool,
+ f: impl FnMut(Local) -> CandidateFilter,
at: Location,
) {
let candidates = entry.get_mut();
- Self::vec_remove_debug(p, candidates, f, at);
+ Self::vec_filter_candidates(p, candidates, f, at);
if candidates.len() == 0 {
entry.remove();
}
}
- /// Removes all candidates `(p, q)` or `(q, p)` where `p` is the indicated local and `f(q)` is true.
- fn remove_candidates_if(&mut self, p: Local, mut f: impl FnMut(Local) -> bool, at: Location) {
+ /// For all candidates `(p, q)` or `(q, p)` removes the candidate if `f(q)` says to do so
+ fn filter_candidates_by(
+ &mut self,
+ p: Local,
+ mut f: impl FnMut(Local) -> CandidateFilter,
+ at: Location,
+ ) {
// Cover the cases where `p` appears as a `src`
if let Entry::Occupied(entry) = self.c.entry(p) {
- Self::entry_remove(entry, p, &mut f, at);
+ Self::entry_filter_candidates(entry, p, &mut f, at);
}
// And the cases where `p` appears as a `dest`
let Some(srcs) = self.reverse.get_mut(&p) else {
// We use `retain` here to remove the elements from the reverse set if we've removed the
// matching candidate in the forward set.
srcs.retain(|src| {
- if !f(*src) {
+ if f(*src) == CandidateFilter::Keep {
return true;
}
let Entry::Occupied(entry) = self.c.entry(*src) else {
return false;
};
- Self::entry_remove(entry, *src, |dest| dest == p, at);
+ Self::entry_filter_candidates(
+ entry,
+ *src,
+ |dest| {
+ if dest == p { CandidateFilter::Remove } else { CandidateFilter::Keep }
+ },
+ at,
+ );
false
});
}
}
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum CandidateFilter {
+ Keep,
+ Remove,
+}
+
impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
/// Filters the set of candidates to remove those that conflict.
///
for (i, statement) in data.statements.iter().enumerate().rev() {
self.at = Location { block, statement_index: i };
self.live.seek_after_primary_effect(self.at);
- self.get_statement_write_info(&statement.kind);
+ self.write_info.for_statement(&statement.kind, self.body);
self.apply_conflicts();
}
}
fn apply_conflicts(&mut self) {
let writes = &self.write_info.writes;
for p in writes {
- self.candidates.remove_candidates_if(
+ let other_skip = self.write_info.skip_pair.and_then(|(a, b)| {
+ if a == *p {
+ Some(b)
+ } else if b == *p {
+ Some(a)
+ } else {
+ None
+ }
+ });
+ self.candidates.filter_candidates_by(
*p,
- // It is possible that a local may be live for less than the
- // duration of a statement This happens in the case of function
- // calls or inline asm. Because of this, we also mark locals as
- // conflicting when both of them are written to in the same
- // statement.
- |q| self.live.contains(q) || writes.contains(&q),
+ |q| {
+ if Some(q) == other_skip {
+ return CandidateFilter::Keep;
+ }
+ // It is possible that a local may be live for less than the
+ // duration of a statement This happens in the case of function
+ // calls or inline asm. Because of this, we also mark locals as
+ // conflicting when both of them are written to in the same
+ // statement.
+ if self.live.contains(q) || writes.contains(&q) {
+ CandidateFilter::Remove
+ } else {
+ CandidateFilter::Keep
+ }
+ },
self.at,
);
}
}
-
- /// Gets the write info for the `statement`.
- fn get_statement_write_info(&mut self, statement: &StatementKind<'tcx>) {
- self.write_info.writes.clear();
- match statement {
- StatementKind::Assign(box (lhs, rhs)) => match rhs {
- Rvalue::Use(op) => {
- if !lhs.is_indirect() {
- self.get_assign_use_write_info(*lhs, op);
- return;
- }
- }
- _ => (),
- },
- _ => (),
- }
-
- self.write_info.for_statement(statement);
- }
-
- fn get_assign_use_write_info(&mut self, lhs: Place<'tcx>, rhs: &Operand<'tcx>) {
- // We register the writes for the operand unconditionally
- self.write_info.add_operand(rhs);
- // However, we cannot do the same thing for the `lhs` as that would always block the
- // optimization. Instead, we consider removing candidates manually.
- let Some(rhs) = rhs.place() else {
- self.write_info.add_place(lhs);
- return;
- };
- // Find out which candidate pair we should skip, if any
- let Some((src, dest)) = places_to_candidate_pair(lhs, rhs, self.body) else {
- self.write_info.add_place(lhs);
- return;
- };
- self.candidates.remove_candidates_if(
- lhs.local,
- |other| {
- // Check if this is the candidate pair that should not be removed
- if (lhs.local == src && other == dest) || (lhs.local == dest && other == src) {
- return false;
- }
- // Otherwise, do the "standard" thing
- self.live.contains(other)
- },
- self.at,
- )
- }
}
/// Describes where a statement/terminator writes to
#[derive(Default, Debug)]
struct WriteInfo {
writes: Vec<Local>,
+ /// If this pair of locals is a candidate pair, completely skip processing it during this
+ /// statement. All other candidates are unaffected.
+ skip_pair: Option<(Local, Local)>,
}
impl WriteInfo {
- fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>) {
+ fn for_statement<'tcx>(&mut self, statement: &StatementKind<'tcx>, body: &Body<'tcx>) {
+ self.reset();
match statement {
StatementKind::Assign(box (lhs, rhs)) => {
self.add_place(*lhs);
match rhs {
- Rvalue::Use(op) | Rvalue::Repeat(op, _) => {
+ Rvalue::Use(op) => {
+ self.add_operand(op);
+ self.consider_skipping_for_assign_use(*lhs, op, body);
+ }
+ Rvalue::Repeat(op, _) => {
self.add_operand(op);
}
Rvalue::Cast(_, op, _)
}
}
+ fn consider_skipping_for_assign_use<'tcx>(
+ &mut self,
+ lhs: Place<'tcx>,
+ rhs: &Operand<'tcx>,
+ body: &Body<'tcx>,
+ ) {
+ let Some(rhs) = rhs.place() else {
+ return
+ };
+ if let Some(pair) = places_to_candidate_pair(lhs, rhs, body) {
+ self.skip_pair = Some(pair);
+ }
+ }
+
fn for_terminator<'tcx>(&mut self, terminator: &TerminatorKind<'tcx>) {
- self.writes.clear();
+ self.reset();
match terminator {
TerminatorKind::SwitchInt { discr: op, .. }
| TerminatorKind::Assert { cond: op, .. } => {
Operand::Copy(_) | Operand::Constant(_) => (),
}
}
+
+ fn reset(&mut self) {
+ self.writes.clear();
+ self.skip_pair = None;
+ }
}
/////////////////////////////////////////////////////
// Candidate accumulation
-fn is_constant<'tcx>(place: Place<'tcx>) -> bool {
- place.projection.iter().all(|p| !matches!(p, ProjectionElem::Deref | ProjectionElem::Index(_)))
-}
-
/// If the pair of places is being considered for merging, returns the candidate which would be
/// merged in order to accomplish this.
///
Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
)) = &statement.kind
{
- if !is_constant(*lhs) || !is_constant(*rhs) {
- return;
- }
-
let Some((src, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
return;
};
};
let kind = match parent_ty.ty.kind() {
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind()
}
kind => kind,
// we must subst the self_ty because it's
// otherwise going to be TySelf and we can't index
// or access fields of a Place of type TySelf.
- let substs = tcx.mk_substs_trait(self_ty, []);
- let sig = tcx.bound_fn_sig(def_id).subst(tcx, substs);
+ let sig = tcx.bound_fn_sig(def_id).subst(tcx, &[self_ty.into()]);
let sig = tcx.erase_late_bound_regions(sig);
let span = tcx.def_span(def_id);
) {
let tcx = self.tcx;
- let substs = tcx.mk_substs_trait(ty, []);
-
// `func == Clone::clone(&ty) -> ty`
- let func_ty = tcx.mk_fn_def(self.def_id, substs);
+ let func_ty = tcx.mk_fn_def(self.def_id, [ty]);
let func = Operand::Constant(Box::new(Constant {
span: self.span,
user_ty: None,
// Create substitutions for the `Self` and `Args` generic parameters of the shim body.
let arg_tup = tcx.mk_tup(untuple_args.iter());
- let sig_substs = tcx.mk_substs_trait(ty, [ty::subst::GenericArg::from(arg_tup)]);
- (Some(sig_substs), Some(untuple_args))
+ (Some([ty.into(), arg_tup.into()]), Some(untuple_args))
} else {
(None, None)
};
assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
let mut sig =
- if let Some(sig_substs) = sig_substs { sig.subst(tcx, sig_substs) } else { sig.0 };
+ if let Some(sig_substs) = sig_substs { sig.subst(tcx, &sig_substs) } else { sig.0 };
if let CallKind::Indirect(fnty) = call_kind {
// `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
V: DefIdVisitor<'tcx> + ?Sized,
{
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> {
- let TraitRef { def_id, substs } = trait_ref;
+ let TraitRef { def_id, substs, .. } = trait_ref;
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
}
fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
let tcx = self.def_id_visitor.tcx();
- let (trait_ref, assoc_substs) = if tcx.def_kind(projection.def_id)
- != DefKind::ImplTraitPlaceholder
- {
- projection.trait_ref_and_own_substs(tcx)
- } else {
- // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
- let def_id = tcx.impl_trait_in_trait_parent(projection.def_id);
- let trait_generics = tcx.generics_of(def_id);
- (
- ty::TraitRef { def_id, substs: projection.substs.truncate_to(tcx, trait_generics) },
- &projection.substs[trait_generics.count()..],
- )
- };
+ let (trait_ref, assoc_substs) =
+ if tcx.def_kind(projection.def_id) != DefKind::ImplTraitPlaceholder {
+ projection.trait_ref_and_own_substs(tcx)
+ } else {
+ // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
+ let def_id = tcx.impl_trait_in_trait_parent(projection.def_id);
+ let trait_generics = tcx.generics_of(def_id);
+ (
+ tcx.mk_trait_ref(def_id, projection.substs.truncate_to(tcx, trait_generics)),
+ &projection.substs[trait_generics.count()..],
+ )
+ };
self.visit_trait(trait_ref)?;
if self.def_id_visitor.shallow() {
ControlFlow::CONTINUE
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)?;
}
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// Skip repeated `Opaque`s to avoid infinite recursion.
if self.visited_opaque_tys.insert(def_id) {
// The intent is to treat `impl Trait1 + Trait2` identically to
pub key: PAuthKey,
}
-#[derive(Clone, Copy, Hash, Debug, PartialEq)]
+#[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
pub struct BranchProtection {
pub bti: bool,
pub pac_ret: Option<PacRet>,
}
-impl Default for BranchProtection {
- fn default() -> Self {
- BranchProtection { bti: false, pac_ret: None }
- }
-}
-
pub const fn default_lib_output() -> CrateType {
CrateType::Rlib
}
.into_iter()
.flat_map(|(i, s)| {
// NB: This can match a string without `=`.
- if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
+ if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
})
.max();
if max_o > max_c {
.into_iter()
.flat_map(|(i, s)| {
// NB: This can match a string without `=`.
- if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
+ if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
})
.max();
if max_g > max_c {
// There might still be a tail left to analyze
let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset;
if tail_start < src.len() {
- analyze_source_file_generic(&src[tail_start as usize ..],
+ analyze_source_file_generic(&src[tail_start ..],
src.len() - tail_start,
output_offset + BytePos::from_usize(tail_start),
lines,
while i < scan_len {
let byte = unsafe {
// We verified that i < scan_len <= src.len()
- *src_bytes.get_unchecked(i as usize)
+ *src_bytes.get_unchecked(i)
};
// How much to advance in order to get to the next UTF-8 char in the
4 => {
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
for diff in diff_iter {
- raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes());
+ raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
}
}
_ => unreachable!(),
/// Otherwise, the span reached to limit is returned.
pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span {
let mut sp = span;
- for _ in 0..limit.unwrap_or(100 as usize) {
+ for _ in 0..limit.unwrap_or(100_usize) {
sp = self.next_point(sp);
if let Ok(ref snippet) = self.span_to_snippet(sp) {
if expect.map_or(false, |es| snippet == es) {
match *ty.kind() {
// Print all nominal types as paths (unlike `pretty_print_type`).
ty::FnDef(def_id, substs)
- | ty::Alias(_, ty::AliasTy { def_id, substs })
+ | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
// Mangle all nominal types as paths.
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
| ty::FnDef(def_id, substs)
- | ty::Alias(_, ty::AliasTy { def_id, substs })
+ | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => {
self = self.print_def_path(def_id, substs)?;
_ => os.into(),
};
- let platform_version: StaticCow<str> = match os.as_ref() {
+ let platform_version: StaticCow<str> = match os {
"ios" => ios_lld_platform_version(),
"tvos" => tvos_lld_platform_version(),
"watchos" => watchos_lld_platform_version(),
base.max_atomic_width = Some(64);
base.add_pre_link_args(
LinkerFlavor::Unix(Cc::No),
- &[
- "-b64".into(),
- "-bpT:0x100000000".into(),
- "-bpD:0x110000000".into(),
- "-bcdtors:all:0:s".into(),
- ],
+ &["-b64", "-bpT:0x100000000", "-bpD:0x110000000", "-bcdtors:all:0:s"],
);
Target {
&& self.fallback_has_occurred
{
let predicate = trait_predicate.map_bound(|trait_pred| {
- trait_pred.with_self_type(self.tcx, self.tcx.mk_unit())
+ trait_pred.with_self_ty(self.tcx, self.tcx.mk_unit())
});
let unit_obligation = obligation.with(tcx, predicate);
if self.predicate_may_hold(&unit_obligation) {
infer::LateBoundRegionConversionTime::HigherRankedType,
bound_predicate.rebind(data),
);
- let normalized_ty = ocx.normalize(
- &obligation.cause,
- obligation.param_env,
- self.tcx.mk_projection(data.projection_ty.def_id, data.projection_ty.substs),
- );
+ let unnormalized_term = match data.term.unpack() {
+ ty::TermKind::Ty(_) => self
+ .tcx
+ .mk_projection(data.projection_ty.def_id, data.projection_ty.substs)
+ .into(),
+ ty::TermKind::Const(ct) => self
+ .tcx
+ .mk_const(
+ ty::UnevaluatedConst {
+ def: ty::WithOptConstParam::unknown(data.projection_ty.def_id),
+ substs: data.projection_ty.substs,
+ },
+ ct.ty(),
+ )
+ .into(),
+ };
+ let normalized_term =
+ ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
debug!(?obligation.cause, ?obligation.param_env);
- debug!(?normalized_ty, data.ty = ?data.term);
+ debug!(?normalized_term, data.ty = ?data.term);
- let is_normalized_ty_expected = !matches!(
+ let is_normalized_term_expected = !matches!(
obligation.cause.code().peel_derives(),
ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ObjectCastObligation(..)
| ObligationCauseCode::OpaqueType
);
- let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error());
// constrain inference variables a bit more to nested obligations from normalize so
// we can have more helpful errors.
if let Err(new_err) = ocx.eq_exp(
&obligation.cause,
obligation.param_env,
- is_normalized_ty_expected,
- normalized_ty,
- expected_ty,
+ is_normalized_term_expected,
+ normalized_term,
+ data.term,
) {
- (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err)
+ (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
} else {
(None, error.err)
}
};
let msg = values
- .and_then(|(predicate, _, normalized_ty, expected_ty)| {
- self.maybe_detailed_projection_msg(
- predicate,
- normalized_ty.into(),
- expected_ty.into(),
- )
+ .and_then(|(predicate, _, normalized_term, expected_term)| {
+ self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
})
.unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
param_env: ty::ParamEnv<'tcx>,
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
) -> PredicateObligation<'tcx> {
- let trait_pred = trait_ref_and_ty
- .map_bound(|(tr, new_self_ty)| tr.with_self_type(self.tcx, new_self_ty));
+ let trait_pred =
+ trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty));
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
}
fn_sig.inputs().map_bound(|inputs| &inputs[1..]),
))
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
if let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) = pred.kind().skip_binder()
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
Some(ident) => err.span_note(ident.span, &msg),
None => err.note(&msg),
},
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// Avoid printing the future from `core::future::identity_future`, it's not helpful
if tcx.parent(*def_id) == identity_future {
break 'print;
self.tcx.mk_projection(
item_def_id,
// Future::Output has no substs
- self.tcx.mk_substs_trait(trait_pred.self_ty(), []),
+ [trait_pred.self_ty()],
)
});
let InferOk { value: projection_ty, .. } =
// in. For example, this would be what `Iterator::Item` is here.
let ty_var = self.infcx.next_ty_var(origin);
// This corresponds to `<ExprTy as Iterator>::Item = _`.
- let trait_ref = ty::Binder::dummy(ty::PredicateKind::Clause(
+ let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
ty::Clause::Projection(ty::ProjectionPredicate {
- projection_ty: ty::AliasTy { substs, def_id: proj.def_id },
+ projection_ty: tcx.mk_alias_ty(proj.def_id, substs),
term: ty_var.into(),
}),
));
span,
expr.hir_id,
param_env,
- trait_ref,
+ projection,
));
if ocx.select_where_possible().is_empty() {
// `ty_var` now holds the type that `Item` is for `ExprTy`.
bound: DefId,
) -> Vec<FulfillmentError<'tcx>> {
let tcx = infcx.tcx;
- let trait_ref = ty::TraitRef { def_id: bound, substs: tcx.mk_substs_trait(ty, []) };
- let obligation = Obligation {
- cause,
- recursion_depth: 0,
- param_env,
- predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
- };
+ let trait_ref = tcx.mk_trait_ref(bound, [ty]);
+ let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref));
fully_solve_obligation(infcx, obligation)
}
// U: Trait<Arg1, ..., ArgN>
let trait_predicate = {
- let substs =
- InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| {
- if param.index == 0 {
- unsized_self_ty.into()
- } else {
- tcx.mk_param_from_def(param)
- }
- });
+ let trait_def_id = method.trait_container(tcx).unwrap();
+ let substs = InternalSubsts::for_item(tcx, trait_def_id, |param, _| {
+ if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
+ });
- ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs })
- .without_const()
- .to_predicate(tcx)
+ ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, substs)).to_predicate(tcx)
};
let caller_bounds: Vec<Predicate<'tcx>> =
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs })
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
if !substs.has_escaping_bound_vars() =>
{
// Only normalize `impl Trait` outside of type inference, usually in codegen.
let trait_substs =
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
// FIXME(named-returns): Binders
- let trait_predicate =
- ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs });
+ let trait_predicate = ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, trait_substs));
let _ = selcx.infcx.commit_if_ok(|_| {
match selcx.select(&obligation.with(tcx, trait_predicate)) {
};
ty::ProjectionPredicate {
- projection_ty: ty::AliasTy {
- substs: trait_ref.substs,
- def_id: obligation.predicate.def_id,
- },
+ projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs),
term: ty.into(),
}
});
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
ty::ProjectionPredicate {
- projection_ty: ty::AliasTy {
- substs: trait_ref.substs,
- def_id: obligation.predicate.def_id,
- },
+ projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.substs),
term: return_ty.into(),
}
});
bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
};
- let predicate = ty::ProjectionPredicate {
- projection_ty: ty::AliasTy { substs, def_id: item_def_id },
- term,
- };
+ let predicate =
+ ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(item_def_id, substs), term };
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
.with_addl_obligations(obligations)
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
- projection_ty: ty::AliasTy { substs: trait_ref.substs, def_id: fn_once_output_def_id },
+ projection_ty: tcx.mk_alias_ty(fn_once_output_def_id, trait_ref.substs),
term: ret_type.into(),
});
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs })
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
if !substs.has_escaping_bound_vars() =>
{
// Only normalize `impl Trait` outside of type inference, usually in codegen.
.kind()
.rebind(
// (*) binder moved here
- ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_type(infcx.tcx, new_self_ty)))
+ ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(infcx.tcx, new_self_ty)))
),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
let ty = traits::normalize_projection_type(
self,
param_env,
- ty::AliasTy { def_id: tcx.lang_items().deref_target()?, substs: trait_ref.substs },
+ tcx.mk_alias_ty(tcx.lang_items().deref_target()?, trait_ref.substs),
cause.clone(),
0,
// We're *intentionally* throwing these away,
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
- ty::Alias(_, ty::AliasTy { def_id, substs }) => (def_id, substs),
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
_ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
};
let tcx = self.infcx.tcx;
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
- ty::Alias(_, ty::AliasTy { def_id, substs }) => (def_id, substs),
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
_ => {
span_bug!(
obligation.cause.span,
t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect())
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
// We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring
// the auto trait bounds in question.
// types appearing in the fn signature
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
// All of the requirements on type parameters
// have already been checked for `impl Trait` in
// return position. We do need to check type-alias-impl-trait though.
}
}
(
- &ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }),
OpaqueType(opaque_ty_id, ..),
) => def_id == opaque_ty_id.0,
(&ty::FnDef(def_id, ..), FnDef(fn_def_id, ..)) => def_id == fn_def_id.0,
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) = *ty.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = *ty.kind() {
if def_id == self.opaque_ty_id.0 && substs == self.identity_substs {
return self.tcx.mk_ty(ty::Bound(
self.binder_index,
ty::Tuple(types) => {
chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner))
}
- ty::Alias(ty::Projection, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Projection, ty::AliasTy { def_id, substs, .. }) => {
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
associated_ty_id: chalk_ir::AssocTypeId(def_id),
substitution: substs.lower_into(interner),
}))
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
substitution: substs.lower_into(interner),
TyKind::Str => ty::Str,
TyKind::OpaqueType(opaque_ty, substitution) => ty::Alias(
ty::Opaque,
- ty::AliasTy { def_id: opaque_ty.0, substs: substitution.lower_into(interner) },
+ interner.tcx.mk_alias_ty(opaque_ty.0, substitution.lower_into(interner)),
),
TyKind::AssociatedType(assoc_ty, substitution) => ty::Alias(
ty::Projection,
- ty::AliasTy { substs: substitution.lower_into(interner), def_id: assoc_ty.0 },
+ interner.tcx.mk_alias_ty(assoc_ty.0, substitution.lower_into(interner)),
),
TyKind::Foreign(def_id) => ty::Foreign(def_id.0),
TyKind::Error => return interner.tcx.ty_error(),
TyKind::Alias(alias_ty) => match alias_ty {
chalk_ir::AliasTy::Projection(projection) => ty::Alias(
ty::Projection,
- ty::AliasTy {
- def_id: projection.associated_ty_id.0,
- substs: projection.substitution.lower_into(interner),
- },
+ interner.tcx.mk_alias_ty(
+ projection.associated_ty_id.0,
+ projection.substitution.lower_into(interner),
+ ),
),
chalk_ir::AliasTy::Opaque(opaque) => ty::Alias(
ty::Opaque,
- ty::AliasTy {
- def_id: opaque.opaque_ty_id.0,
- substs: opaque.substitution.lower_into(interner),
- },
+ interner.tcx.mk_alias_ty(
+ opaque.opaque_ty_id.0,
+ opaque.substitution.lower_into(interner),
+ ),
),
},
TyKind::Function(_quantified_ty) => unimplemented!(),
def_id: DefId,
substs: ty::SubstsRef<'tcx>,
) -> (Vec<VariantInfo>, Option<Size>) {
- let Variants::Multiple { tag, ref tag_encoding, .. } = layout.variants else {
+ let Variants::Multiple { tag, ref tag_encoding, tag_field, .. } = layout.variants else {
return (vec![], None);
};
if variant_size == Size::ZERO {
variant_size = upvars_size;
}
- // We need to add the discriminant size back into min_size, since it is subtracted
- // later during printing.
- variant_size += match tag_encoding {
- TagEncoding::Direct => tag.size(cx),
- _ => Size::ZERO,
- };
+
+ // This `if` deserves some explanation.
+ //
+ // The layout code has a choice of where to place the discriminant of this generator.
+ // If the discriminant of the generator is placed early in the layout (before the
+ // variant's own fields), then it'll implicitly be counted towards the size of the
+ // variant, since we use the maximum offset to calculate size.
+ // (side-note: I know this is a bit problematic given upvars placement, etc).
+ //
+ // This is important, since the layout printing code always subtracts this discriminant
+ // size from the variant size if the struct is "enum"-like, so failing to account for it
+ // will either lead to numerical underflow, or an underreported variant size...
+ //
+ // However, if the discriminant is placed past the end of the variant, then we need
+ // to factor in the size of the discriminant manually. This really should be refactored
+ // better, but this "works" for now.
+ if layout.fields.offset(tag_field) >= variant_size {
+ variant_size += match tag_encoding {
+ TagEncoding::Direct => tag.size(cx),
+ _ => Size::ZERO,
+ };
+ }
VariantInfo {
name: Some(Symbol::intern(&ty::GeneratorSubsts::variant_name(variant_idx))),
match self {
Bool => Bool,
Char => Char,
- Int(i) => Int(i.clone()),
- Uint(u) => Uint(u.clone()),
- Float(f) => Float(f.clone()),
+ Int(i) => Int(*i),
+ Uint(u) => Uint(*u),
+ Float(f) => Float(*f),
Adt(d, s) => Adt(d.clone(), s.clone()),
Foreign(d) => Foreign(d.clone()),
Str => Str,
Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()),
FnDef(d, s) => FnDef(d.clone(), s.clone()),
FnPtr(s) => FnPtr(s.clone()),
- Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), repr.clone()),
+ Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), *repr),
Closure(d, s) => Closure(d.clone(), s.clone()),
Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()),
GeneratorWitness(g) => GeneratorWitness(g.clone()),
Tuple(t) => Tuple(t.clone()),
Alias(k, p) => Alias(*k, p.clone()),
Param(p) => Param(p.clone()),
- Bound(d, b) => Bound(d.clone(), b.clone()),
+ Bound(d, b) => Bound(*d, b.clone()),
Placeholder(p) => Placeholder(p.clone()),
Infer(t) => Infer(t.clone()),
Error(e) => Error(e.clone()),
fn clone(&self) -> Self {
match self {
ReEarlyBound(r) => ReEarlyBound(r.clone()),
- ReLateBound(d, r) => ReLateBound(d.clone(), r.clone()),
+ ReLateBound(d, r) => ReLateBound(*d, r.clone()),
ReFree(r) => ReFree(r.clone()),
ReStatic => ReStatic,
ReVar(r) => ReVar(r.clone()),
use crate::sys::common::small_c_string::run_path_with_cstr;
use crate::sys::{cvt, cvt_r};
- #[cfg(not(all(target_os = "macos", not(target_arch = "aarch64")),))]
+ #[cfg(not(any(
+ target_os = "linux",
+ all(target_os = "macos", not(target_arch = "aarch64"))
+ )))]
use libc::{fdopendir, openat, unlinkat};
+ #[cfg(target_os = "linux")]
+ use libc::{fdopendir, openat64 as openat, unlinkat};
#[cfg(all(target_os = "macos", not(target_arch = "aarch64")))]
use macos_weak::{fdopendir, openat, unlinkat};
use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use crate::sys::cvt;
use crate::sys::weak::syscall;
+#[cfg(not(target_os = "linux"))]
+use libc::sendfile as sendfile64;
+#[cfg(target_os = "linux")]
+use libc::sendfile64;
use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV};
#[cfg(test)]
let result = match mode {
SpliceMode::Sendfile => {
- cvt(unsafe { libc::sendfile(writer, reader, ptr::null_mut(), chunk_size) })
+ cvt(unsafe { sendfile64(writer, reader, ptr::null_mut(), chunk_size) })
}
SpliceMode::Splice => cvt(unsafe {
splice(reader, ptr::null_mut(), writer, ptr::null_mut(), chunk_size, 0)
)))]
'poll: {
use crate::sys::os::errno;
+ #[cfg(not(target_os = "linux"))]
+ use libc::open as open64;
+ #[cfg(target_os = "linux")]
+ use libc::open64;
let pfds: &mut [_] = &mut [
libc::pollfd { fd: 0, events: 0, revents: 0 },
libc::pollfd { fd: 1, events: 0, revents: 0 },
if pfd.revents & libc::POLLNVAL == 0 {
continue;
}
- if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+ if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
// If the stream is closed but we failed to reopen it, abort the
// process. Otherwise we wouldn't preserve the safety of
// operations on the corresponding Rust object Stdin, Stdout, or
)))]
{
use crate::sys::os::errno;
+ #[cfg(not(target_os = "linux"))]
+ use libc::open as open64;
+ #[cfg(target_os = "linux")]
+ use libc::open64;
for fd in 0..3 {
if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
- if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+ if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
// If the stream is closed but we failed to reopen it, abort the
// process. Otherwise we wouldn't preserve the safety of
// operations on the corresponding Rust object Stdin, Stdout, or
//
// Note that as soon as we're done with the fork there's no need to hold
// a lock any more because the parent won't do anything and the child is
- // in its own process. Thus the parent drops the lock guard while the child
- // forgets it to avoid unlocking it on a new thread, which would be invalid.
+ // in its own process. Thus the parent drops the lock guard immediately.
+ // The child calls `mem::forget` to leak the lock, which is crucial because
+ // releasing a lock is not async-signal-safe.
let env_lock = sys::os::env_read_lock();
let (pid, pidfd) = unsafe { self.do_fork()? };
if pid == 0 {
crate::panic::always_abort();
- mem::forget(env_lock);
+ mem::forget(env_lock); // avoid non-async-signal-safe unlocking
drop(input);
let Err(err) = unsafe { self.do_exec(theirs, envp.as_ref()) };
let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32;
use crate::thread;
use libc::MAP_FAILED;
- use libc::{mmap, munmap};
+ #[cfg(not(target_os = "linux"))]
+ use libc::{mmap as mmap64, munmap};
+ #[cfg(target_os = "linux")]
+ use libc::{mmap64, munmap};
use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL};
use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV};
#[cfg(not(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",)))]
let flags = MAP_PRIVATE | MAP_ANON;
let stackp =
- mmap(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0);
+ mmap64(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0);
if stackp == MAP_FAILED {
panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error());
}
))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- use libc::{mmap, mprotect};
+ #[cfg(not(target_os = "linux"))]
+ use libc::{mmap as mmap64, mprotect};
+ #[cfg(target_os = "linux")]
+ use libc::{mmap64, mprotect};
use libc::{MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
use crate::io;
// read/write permissions and only then mprotect() it to
// no permissions at all. See issue #50313.
let stackptr = get_stack_start_aligned()?;
- let result = mmap(
+ let result = mmap64(
stackptr,
page_size,
PROT_READ | PROT_WRITE,
impl<T: Internable + Deref> Deref for Interned<T> {
type Target = T::Target;
- fn deref(&self) -> &'static Self::Target {
+ fn deref(&self) -> &Self::Target {
let l = T::intern_cache().lock().unwrap();
- unsafe { mem::transmute::<&Self::Target, &'static Self::Target>(l.get(*self)) }
+ unsafe { mem::transmute::<&Self::Target, &Self::Target>(l.get(*self)) }
}
}
impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
- fn as_ref(&self) -> &'static U {
+ fn as_ref(&self) -> &U {
let l = T::intern_cache().lock().unwrap();
- unsafe { mem::transmute::<&U, &'static U>(l.get(*self).as_ref()) }
+ unsafe { mem::transmute::<&U, &U>(l.get(*self).as_ref()) }
}
}
}
}
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the bounds associated with the def_id.
let bounds = cx
return event;
};
- let mut origtext = String::new();
+ let mut original_text = String::new();
for event in &mut self.inner {
match event {
Event::End(Tag::CodeBlock(..)) => break,
Event::Text(ref s) => {
- origtext.push_str(s);
+ original_text.push_str(s);
}
_ => {}
}
<pre class=\"language-{}\"><code>{}</code></pre>\
</div>",
lang,
- Escape(&origtext),
+ Escape(&original_text),
)
.into(),
));
CodeBlockKind::Indented => Default::default(),
};
- let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
+ let lines = original_text.lines().filter_map(|l| map_line(l).for_html());
let text = lines.intersperse("\n".into()).collect::<String>();
compile_fail = parse_result.compile_fail;
if url.is_empty() {
return None;
}
- let test = origtext
+ let test = original_text
.lines()
.map(|l| map_line(l).for_code())
.intersperse("\n".into())
vertical-align: middle;
border: solid 1px var(--border-color);
border-radius: 3px;
- cursor: default;
color: var(--kbd--color);
background-color: var(--kbd-background);
box-shadow: inset 0 -1px 0 var(--kbd-box-shadow-color);
}
.scraped-example .code-wrapper .src-line-numbers {
- margin: 0;
padding: 14px 0;
}
// It also validates that functions can be called through function pointers
// through traits.
-#![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)]
+#![feature(no_core, lang_items, intrinsics, unboxed_closures, arbitrary_self_types)]
#![crate_type = "lib"]
#![no_core]
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
+extern "rust-intrinsic" {
+ pub fn transmute<Src, Dst>(src: Src) -> Dst;
+}
+
pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
pub static mut STORAGE_BAR: u32 = 12;
STORAGE_FOO(&1, &mut buf);
}
}
+
+// Validate that we can codegen transmutes between data ptrs and fn ptrs.
+
+// CHECK: define{{.+}}{{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}} @transmute_data_ptr_to_fn({{\{\}\*|ptr}}{{.*}} %x)
+#[no_mangle]
+pub unsafe fn transmute_data_ptr_to_fn(x: *const ()) -> fn() {
+ // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
+ // as long as it doesn't cause a verifier error by using `bitcast`.
+ transmute(x)
+}
+
+// CHECK: define{{.+}}{{\{\}\*|ptr}} @transmute_fn_ptr_to_data({{void \(\) addrspace\(1\)\*|ptr addrspace\(1\)}}{{.*}} %x)
+#[no_mangle]
+pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
+ // It doesn't matter precisely how this is codegenned (through memory or an addrspacecast),
+ // as long as it doesn't cause a verifier error by using `bitcast`.
+ transmute(x)
+}
"color": |color|,
"background-color": |background|,
"box-shadow": |box_shadow| + " 0px -1px 0px 0px inset",
- "cursor": "default",
}, ALL)),
],
)
--- /dev/null
+use std::fmt::Display;
+
+fn foo(x: &(dyn Display + Send)) {}
+
+fn main() {
+ foo();
+ //~^ ERROR this function takes 1 argument but 0 arguments were supplied
+}
--- /dev/null
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+ --> $DIR/display-is-suggestable.rs:6:5
+ |
+LL | foo();
+ | ^^^-- an argument of type `&dyn std::fmt::Display + Send` is missing
+ |
+note: function defined here
+ --> $DIR/display-is-suggestable.rs:3:4
+ |
+LL | fn foo(x: &(dyn Display + Send)) {}
+ | ^^^ ------------------------
+help: provide the argument
+ |
+LL | foo(/* &dyn std::fmt::Display + Send */);
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
--- /dev/null
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/const-projection-err.rs:4:26
+ |
+LL | #![cfg_attr(gce, feature(generic_const_exprs))]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+ --> $DIR/const-projection-err.rs:14:11
+ |
+LL | foo::<T>();
+ | ^ expected `0`, found `1`
+ |
+note: required by a bound in `foo`
+ --> $DIR/const-projection-err.rs:11:28
+ |
+LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
+ | ^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0271`.
--- /dev/null
+// revisions: stock gce
+
+#![feature(associated_const_equality)]
+#![cfg_attr(gce, feature(generic_const_exprs))]
+//[gce]~^ WARN the feature `generic_const_exprs` is incomplete
+
+trait TraitWAssocConst {
+ const A: usize;
+}
+
+fn foo<T: TraitWAssocConst<A = 1>>() {}
+
+fn bar<T: TraitWAssocConst<A = 0>>() {
+ foo::<T>();
+ //~^ ERROR type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+}
+
+fn main() {}
--- /dev/null
+error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
+ --> $DIR/const-projection-err.rs:14:11
+ |
+LL | foo::<T>();
+ | ^ expected `1`, found `<T as TraitWAssocConst>::A`
+ |
+ = note: expected constant `1`
+ found constant `<T as TraitWAssocConst>::A`
+note: required by a bound in `foo`
+ --> $DIR/const-projection-err.rs:11:28
+ |
+LL | fn foo<T: TraitWAssocConst<A = 1>>() {}
+ | ^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
-// check-pass
// edition: 2021
#![feature(async_fn_in_trait)]
}
impl MyTrait for i32 {
- // This will break once a PR that implements #102745 is merged
fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
- Box::pin(async {
- *self
- })
+ //~^ ERROR method `foo` should be async
+ Box::pin(async { *self })
}
}
--- /dev/null
+error: method `foo` should be async because the method from the trait is async
+ --> $DIR/async-example-desugared-boxed.rs:15:5
+ |
+LL | async fn foo(&self) -> i32;
+ | --------------------------- required because the trait method is async
+...
+LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::Poll;
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+}
+
+#[derive(Clone)]
+struct MyFuture(i32);
+
+impl Future for MyFuture {
+ type Output = i32;
+ fn poll(
+ self: Pin<&mut Self>,
+ _: &mut std::task::Context<'_>,
+ ) -> Poll<<Self as Future>::Output> {
+ Poll::Ready(self.0)
+ }
+}
+
+impl MyTrait for i32 {
+ // FIXME: this should eventually require `#[refine]` to compile, because it also provides
+ // `Clone`.
+ fn foo(&self) -> impl Future<Output = i32> + Clone {
+ MyFuture(*self)
+ }
+}
+
+fn main() {}
--- /dev/null
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::task::Poll;
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+}
+
+struct MyFuture;
+impl Future for MyFuture {
+ type Output = i32;
+ fn poll(self: std::pin::Pin<&mut Self>, _: &mut std::task::Context<'_>) -> Poll<Self::Output> {
+ Poll::Ready(0)
+ }
+}
+
+impl MyTrait for u32 {
+ fn foo(&self) -> MyFuture {
+ //~^ ERROR method `foo` should be async
+ MyFuture
+ }
+}
+
+fn main() {}
--- /dev/null
+error: method `foo` should be async because the method from the trait is async
+ --> $DIR/async-example-desugared-manual.rs:23:5
+ |
+LL | async fn foo(&self) -> i32;
+ | --------------------------- required because the trait method is async
+...
+LL | fn foo(&self) -> MyFuture {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
}
impl MyTrait for i32 {
- // This will break once a PR that implements #102745 is merged
fn foo(&self) -> impl Future<Output = i32> + '_ {
- async {
- *self
- }
+ async { *self }
}
}
impl MyTrait for i32 {
fn foo(&self) -> i32 {
- //~^ ERROR: `i32` is not a future [E0277]
+ //~^ ERROR: method `foo` should be async
*self
}
}
-error[E0277]: `i32` is not a future
- --> $DIR/fn-not-async-err.rs:11:22
- |
-LL | fn foo(&self) -> i32 {
- | ^^^ `i32` is not a future
- |
- = help: the trait `Future` is not implemented for `i32`
- = note: i32 must be a future or must implement `IntoFuture` to be awaited
-note: required by a bound in `MyTrait::foo::{opaque#0}`
- --> $DIR/fn-not-async-err.rs:7:28
+error: method `foo` should be async because the method from the trait is async
+ --> $DIR/fn-not-async-err.rs:11:5
|
LL | async fn foo(&self) -> i32;
- | ^^^ required by this bound in `MyTrait::foo::{opaque#0}`
+ | --------------------------- required because the trait method is async
+...
+LL | fn foo(&self) -> i32 {
+ | ^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
impl MyTrait for i32 {
fn foo(&self) -> impl Future<Output = i32> {
//~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `impl` method return [E0562]
- async {
- *self
- }
+ async { *self }
}
}
--- /dev/null
+// edition:2021
+// check-pass
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+pub trait Pool {
+ type Conn;
+
+ async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future<Output = ()>>(
+ &'a self,
+ callback: F,
+ ) -> ();
+}
+
+pub struct PoolImpl;
+pub struct ConnImpl;
+
+impl Pool for PoolImpl {
+ type Conn = ConnImpl;
+
+ async fn async_callback<'a, F: FnOnce(&'a Self::Conn) -> Fut, Fut: Future<Output = ()>>(
+ &'a self,
+ _callback: F,
+ ) -> () {
+ todo!()
+ }
+}
+
+fn main() {}
--- /dev/null
+// edition:2018
+// check-pass
+
+#![allow(dead_code)]
+async fn fail<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, {}
+async fn pass<'a, 'c, 'b>(_: &'static str) where 'a: 'c, 'b: 'c, {}
+async fn pass2<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, 'c: 'a, {}
+async fn pass3<'a, 'b, 'c>(_: &'static str) where 'a: 'b, 'b: 'c, 'c: 'a, {}
+
+fn main() { }
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
- | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds
+ | ^^^^^^ method cannot be called due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
--> $DIR/issue-105330.rs:12:11
|
LL | foo::<Demo>()();
- | ^^^^ types differ
+ | ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
|
+ = note: expected constant `32`
+ found constant `<Demo as TraitWAssocConst>::A`
note: required by a bound in `foo`
--> $DIR/issue-105330.rs:11:28
|
--> $DIR/issue-105330.rs:19:11
|
LL | foo::<Demo>();
- | ^^^^ types differ
+ | ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
|
+ = note: expected constant `32`
+ found constant `<Demo as TraitWAssocConst>::A`
note: required by a bound in `foo`
--> $DIR/issue-105330.rs:11:28
|
--> $DIR/issue-31173.rs:12:10
|
LL | .collect();
- | ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called due to unsatisfied trait bounds
--> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL
|
= note: doesn't satisfy `<_ as Iterator>::Item = &_`
--> $DIR/issue-36053-2.rs:7:55
|
LL | once::<&str>("str").fuse().filter(|a: &str| true).count();
- | --------- ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>` due to unsatisfied trait bounds
+ | --------- ^^^^^ method cannot be called due to unsatisfied trait bounds
| |
| doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
| doesn't satisfy `_: FnMut<(&&str,)>`
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type lib
// edition:2021
// build-pass
// ignore-pass
-#![feature(start)]
-
async fn wait() {}
-async fn test(arg: [u8; 8192]) {
+pub async fn test(arg: [u8; 8192]) {
wait().await;
drop(arg);
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _ = test([0; 8192]);
- 0
-}
-print-type-size type: `[async fn body@$DIR/async.rs:10:32: 13:2]`: 16386 bytes, alignment: 1 bytes
+print-type-size type: `[async fn body@$DIR/async.rs:8:36: 11:2]`: 16386 bytes, alignment: 1 bytes
print-type-size discriminant: 1 bytes
print-type-size variant `Suspend0`: 16385 bytes
print-type-size field `.arg`: 8192 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size variant `MaybeUninit`: 8192 bytes
print-type-size field `.uninit`: 0 bytes
print-type-size field `.value`: 8192 bytes
-print-type-size type: `[async fn body@$DIR/async.rs:8:17: 8:19]`: 1 bytes, alignment: 1 bytes
+print-type-size type: `[async fn body@$DIR/async.rs:6:17: 6:19]`: 1 bytes, alignment: 1 bytes
print-type-size discriminant: 1 bytes
print-type-size variant `Unresumed`: 0 bytes
print-type-size variant `Returned`: 0 bytes
print-type-size variant `Panicked`: 0 bytes
-print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes
print-type-size field `.value`: 1 bytes
-print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes
+print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes
print-type-size variant `MaybeUninit`: 1 bytes
print-type-size field `.uninit`: 0 bytes
print-type-size field `.value`: 1 bytes
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
-#![feature(start, generators, generator_trait)]
+#![feature(generators, generator_trait)]
use std::ops::Generator;
}
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn foo() {
let _ = generator([0; 8192]);
- 0
}
--- /dev/null
+// compile-flags: -Z print-type-sizes --crate-type lib
+// build-pass
+// ignore-pass
+
+// Tests a generator that has its discriminant as the *final* field.
+
+// Avoid emitting panic handlers, like the rest of these tests...
+#![feature(generators)]
+
+pub fn foo() {
+ let a = || {
+ {
+ let w: i32 = 4;
+ yield;
+ drop(w);
+ }
+ {
+ let z: i32 = 7;
+ yield;
+ drop(z);
+ }
+ };
+}
--- /dev/null
+print-type-size type: `[generator@$DIR/generator_discr_placement.rs:11:13: 11:15]`: 8 bytes, alignment: 4 bytes
+print-type-size discriminant: 1 bytes
+print-type-size variant `Suspend0`: 7 bytes
+print-type-size padding: 3 bytes
+print-type-size field `.w`: 4 bytes, alignment: 4 bytes
+print-type-size variant `Suspend1`: 7 bytes
+print-type-size padding: 3 bytes
+print-type-size field `.z`: 4 bytes, alignment: 4 bytes
+print-type-size variant `Unresumed`: 0 bytes
+print-type-size variant `Returned`: 0 bytes
+print-type-size variant `Panicked`: 0 bytes
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// monomorphized, in the MIR of the original function in which they
// occur, to have their size reported.
-#![feature(start)]
-
-// In an ad-hoc attempt to avoid the injection of unwinding code
-// (which clutters the output of `-Z print-type-sizes` with types from
-// `unwind::libunwind`):
-//
-// * I am not using Default to build values because that seems to
-// cause the injection of unwinding code. (Instead I just make `fn new`
-// methods.)
-//
-// * Pair derive Copy to ensure that we don't inject
-// unwinding code into generic uses of Pair when T itself is also
-// Copy.
-//
-// (I suspect this reflect some naivety within the rust compiler
-// itself; it should be checking for drop glue, i.e., a destructor
-// somewhere in the monomorphized types. It should not matter whether
-// the type is Copy.)
#[derive(Copy, Clone)]
pub struct Pair<T> {
_car: T,
Pair::new(FiftyBytes::new(), FiftyBytes::new());
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn start() {
let _b: Pair<u8> = Pair::new(0, 0);
let _s: Pair<SevenBytes> = Pair::new(SevenBytes::new(), SevenBytes::new());
let ref _z: ZeroSized = ZeroSized;
f1::<SevenBytes>(SevenBytes::new());
- 0
}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// This file illustrates that when multiple structural types occur in
// a function, every one of them is included in the output.
-#![feature(start)]
-
pub struct SevenBytes([u8; 7]);
pub struct FiftyBytes([u8; 50]);
Small(SevenBytes),
Large(FiftyBytes),
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _e: Enum;
- let _f: FiftyBytes;
- let _s: SevenBytes;
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// aligned (while on most it is 8-byte aligned) and so the resulting
// padding and overall computed sizes can be quite different.
-#![feature(start)]
#![feature(rustc_attrs)]
#![allow(dead_code)]
impl Default for NestedNonZero {
fn default() -> Self {
- NestedNonZero { pre: 0, val: NonZeroU32::new(1).unwrap(), post: 0 }
+ NestedNonZero { pre: 0, val: unsafe { NonZeroU32::new_unchecked(1) }, post: 0 }
}
}
b: B,
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
let _x: MyOption<NonZeroU32> = Default::default();
let _y: EmbeddedDiscr = Default::default();
let _z: MyOption<IndirectNonZero> = Default::default();
// ...even when theoretically possible.
let _j: MyOption<Union1<NonZeroU32>> = Default::default();
let _k: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();
-
- 0
}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// (even if multiple functions), it is only printed once in the
// print-type-sizes output.
-#![feature(start)]
-
pub struct SevenBytes([u8; 7]);
pub fn f1() {
let _s: SevenBytes = SevenBytes([0; 7]);
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
let _s: SevenBytes = SevenBytes([0; 7]);
- 0
}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// padding and overall computed sizes can be quite different.
#![allow(dead_code)]
-#![feature(start)]
#[derive(Default)]
#[repr(packed)]
-struct Packed1 {
+pub struct Packed1 {
a: u8,
b: u8,
g: i32,
#[derive(Default)]
#[repr(packed(2))]
-struct Packed2 {
+pub struct Packed2 {
a: u8,
b: u8,
g: i32,
#[derive(Default)]
#[repr(packed(2))]
#[repr(C)]
-struct Packed2C {
+pub struct Packed2C {
a: u8,
b: u8,
g: i32,
}
#[derive(Default)]
-struct Padded {
+pub struct Padded {
a: u8,
b: u8,
g: i32,
h: i16,
d: u8,
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _c: Packed1 = Default::default();
- let _d: Packed2 = Default::default();
- let _e: Packed2C = Default::default();
- let _f: Padded = Default::default();
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// This file illustrates how padding is handled: alignment
// aligned (while on most it is 8-byte aligned) and so the resulting
// padding and overall computed sizes can be quite different.
-#![feature(start)]
#![allow(dead_code)]
struct S {
A(i8, i32),
B(S),
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// It avoids using u64/i64 because on some targets that is only 4-byte
// aligned (while on most it is 8-byte aligned) and so the resulting
// padding and overall computed sizes can be quite different.
-#![feature(start)]
+
#![allow(dead_code)]
#[repr(align(16))]
}
#[derive(Default)]
-struct S {
+pub struct S {
a: i32,
b: i32,
c: A,
d: i8,
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _s: S = Default::default();
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)`
// variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug).
-#![feature(start)]
#![allow(dead_code)]
#[repr(C, u8)]
A(u16),
B,
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// ^-- needed because `--pass check` does not emit the output needed.
// FIXME: consider using an attribute instead of side-effects.
#![feature(never_type)]
-#![feature(start)]
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
let _x: Option<!> = None;
let _y: Result<u32, !> = Ok(42);
let _z: Result<!, !> = loop {};
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// This file illustrates two things:
// 2. For an enum, the print-type-sizes output will also include the
// size of each variant.
-#![feature(start)]
-
pub struct SevenBytes([u8; 7]);
pub struct FiftyBytes([u8; 50]);
Small(SevenBytes),
Large(FiftyBytes),
}
-
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
- let _e: Enum;
- 0
-}
-// compile-flags: -Z print-type-sizes
+// compile-flags: -Z print-type-sizes --crate-type=lib
// build-pass
// ignore-pass
// At one point, zero-sized fields such as those in this file were causing
// incorrect output from `-Z print-type-sizes`.
-#![feature(start)]
-
struct S1 {
x: u32,
y: u32,
tagz: TagZ,
}
-#[start]
-fn start(_: isize, _: *const *const u8) -> isize {
+pub fn test() {
let _s1: S1 = S1 { x: 0, y: 0, tag: () };
let _s5: S5<(), Empty> = S5 {
z: 4,
tagz: Empty {},
};
- 0
}
--- /dev/null
+//check-fail
+
+#![crate_type="lib"]
+
+fn r({) {
+ Ok { //~ ERROR mismatched types [E0308]
+ d..||_=m
+ }
+}
+//~^^^^^ ERROR expected parameter name, found `{`
+//~| ERROR expected one of `,`, `:`, or `}`, found `..`
+//~^^^^^ ERROR cannot find value `d` in this scope [E0425]
+//~| ERROR cannot find value `m` in this scope [E0425]
+//~| ERROR variant `Result<_, _>::Ok` has no field named `d` [E0559]
--- /dev/null
+error: expected parameter name, found `{`
+ --> $DIR/issue-92481.rs:5:6
+ |
+LL | fn r({) {
+ | ^ expected parameter name
+
+error: expected one of `,`, `:`, or `}`, found `..`
+ --> $DIR/issue-92481.rs:5:6
+ |
+LL | fn r({) {
+ | ^ unclosed delimiter
+LL | Ok {
+LL | d..||_=m
+ | -^
+ | |
+ | help: `}` may belong here
+
+error[E0425]: cannot find value `d` in this scope
+ --> $DIR/issue-92481.rs:7:9
+ |
+LL | d..||_=m
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `m` in this scope
+ --> $DIR/issue-92481.rs:7:16
+ |
+LL | d..||_=m
+ | ^ not found in this scope
+
+error[E0559]: variant `Result<_, _>::Ok` has no field named `d`
+ --> $DIR/issue-92481.rs:7:9
+ |
+LL | d..||_=m
+ | ^ field does not exist
+ --> $SRC_DIR/core/src/result.rs:LL:COL
+ |
+ = note: `Result<_, _>::Ok` defined here
+ |
+help: `Result<_, _>::Ok` is a tuple variant, use the appropriate syntax
+ |
+LL | Result<_, _>::Ok(/* fields */)
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/issue-92481.rs:6:5
+ |
+LL | fn r({) {
+ | - help: a return type might be missing here: `-> _`
+LL | / Ok {
+LL | | d..||_=m
+LL | | }
+ | |_____^ expected `()`, found enum `Result`
+ |
+ = note: expected unit type `()`
+ found enum `Result<_, _>`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0425, E0559.
+For more information about an error, try `rustc --explain E0308`.
-Subproject commit 70898e522116f6c23971e2a554b2dc85fd4c84cd
+Subproject commit cc0a320879c17207bbfb96b5d778e28a2c62030d
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{
self, Binder, BoundConstness, Clause, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate,
- TraitRef, Ty, TyCtxt,
+ Ty, TyCtxt,
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
- trait_ref: TraitRef::new(
+ trait_ref: tcx.mk_trait_ref(
eq_trait_id,
- tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))),
+ [tcx.mk_param_from_def(param)],
),
constness: BoundConstness::NotConst,
polarity: ImplPolarity::Positive,
return;
}
let ret_ty = return_ty(cx, hir_id);
- if let ty::Alias(ty::Opaque, AliasTy { def_id, substs }) = *ret_ty.kind() {
+ if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
let preds = cx.tcx.explicit_item_bounds(def_id);
let mut is_future = false;
for &(p, _span) in preds {
return true;
}
- if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) = *inner_ty.kind() {
+ if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
match predicate.kind().skip_binder() {
// For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
is_must_use_ty(cx, *ty)
},
ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => {
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() {
if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
},
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs: _ }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
+ ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
ty::Dynamic(bounds, _, _) => {
let lang_items = cx.tcx.lang_items();
}
}
- Some(AliasTy {
+ Some(tcx.mk_alias_ty(
+ assoc_item.def_id,
substs,
- def_id: assoc_item.def_id,
- })
+ ))
}
helper(
tcx,
("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
+ ("cranelift-egraph", "Apache-2.0 WITH LLVM-exception"),
("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
("cranelift-isle", "Apache-2.0 WITH LLVM-exception"),
("mach", "BSD-2-Clause"),
("regalloc2", "Apache-2.0 WITH LLVM-exception"),
("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
+ ("wasmtime-jit-icache-coherence", "Apache-2.0 WITH LLVM-exception"),
];
const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[
"cranelift-codegen",
"cranelift-codegen-meta",
"cranelift-codegen-shared",
+ "cranelift-egraph",
"cranelift-entity",
"cranelift-frontend",
"cranelift-isle",
"cranelift-native",
"cranelift-object",
"crc32fast",
+ "fallible-iterator",
"fxhash",
"getrandom",
"gimli",
"region",
"slice-group-by",
"smallvec",
+ "stable_deref_trait",
"target-lexicon",
"version_check",
"wasi",
+ "wasmtime-jit-icache-coherence",
"winapi",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
"@compiler-errors",
"@eholk",
"@jackh726",
- "@fee1-dead",
"@TaKO8Ki",
"@Nilstrieb",
]