diff --git a/Cargo.lock b/Cargo.lock index f15f9519cb34f..8bfdf23a30bf4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4133,6 +4133,7 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", + "rustc_trait_selection", "rustc_typeck", "tracing", ] diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index e6d3375fb1bab..20c58423a0c50 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -12,6 +12,9 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] + env: + - BACKEND: "" + - BACKEND: --oldbe steps: - uses: actions/checkout@v2 @@ -51,7 +54,7 @@ jobs: export COMPILE_RUNS=2 export RUN_RUNS=2 - ./test.sh + ./test.sh $BACKEND - name: Package prebuilt cg_clif run: tar cvfJ cg_clif.tar.xz build diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore index 18196bce00945..b241bef9d1e7f 100644 --- a/compiler/rustc_codegen_cranelift/.gitignore +++ b/compiler/rustc_codegen_cranelift/.gitignore @@ -8,6 +8,7 @@ perf.data.old *.string* /build /build_sysroot/sysroot_src +/build_sysroot/compiler-builtins /rust /rand /regex diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index 7618251acd5c2..19ea41563dfd6 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -1,7 +1,7 @@ { // source for rustc_* is not included in the rust-src component; disable the errors about this "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate"], - "rust-analyzer.assist.importMergeBehaviour": "last", + "rust-analyzer.assist.importMergeBehavior": "last", "rust-analyzer.cargo.loadOutDirsFromCheck": true, "rust-analyzer.linkedProjects": [ "./Cargo.toml", diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 0382835269d1f..5495cfa5eaa0d 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "anyhow" -version = "1.0.34" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "ar" @@ -25,15 +25,15 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" [[package]] name = "cc" -version = "1.0.62" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" [[package]] name = "cfg-if" @@ -49,16 +49,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" dependencies = [ "byteorder", "cranelift-bforest", @@ -75,8 +75,8 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -84,18 +84,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" [[package]] name = "cranelift-entity" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" [[package]] name = "cranelift-frontend" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" dependencies = [ "cranelift-codegen", "log", @@ -105,8 +105,8 @@ dependencies = [ [[package]] name = "cranelift-jit" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" dependencies = [ "anyhow", "cranelift-codegen", @@ -123,8 +123,8 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" dependencies = [ "anyhow", "cranelift-codegen", @@ -135,8 +135,8 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" dependencies = [ "cranelift-codegen", "raw-cpuid", @@ -145,8 +145,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.68.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8f7f8ee0b4c5007ace6de29b45505c360450b1bb" +version = "0.69.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca" dependencies = [ "anyhow", "cranelift-codegen", @@ -209,9 +209,9 @@ checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" [[package]] name = "indexmap" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" +checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" dependencies = [ "autocfg", "hashbrown", @@ -219,15 +219,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.80" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" [[package]] name = "libloading" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" dependencies = [ "cfg-if 1.0.0", "winapi", @@ -235,9 +235,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" dependencies = [ "cfg-if 0.1.10", ] @@ -272,9 +272,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -333,6 +333,7 @@ dependencies = [ "indexmap", "libloading", "object", + "smallvec", "target-lexicon", ] @@ -362,15 +363,15 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "smallvec" -version = "1.4.2" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.48" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" +checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5" dependencies = [ "proc-macro2", "quote", @@ -385,18 +386,18 @@ checksum = "4ee5a98e506fb7231a304c3a1bd7c132a55016cf65001e0282480665870dfcb9" [[package]] name = "thiserror" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ "proc-macro2", "quote", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 8e1933bb14e7c..3820fce6d1e0d 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] } +cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind", "x86", "x64"] } cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true } @@ -21,6 +21,7 @@ object = { version = "0.22.0", default-features = false, features = ["std", "rea ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.0.2" libloading = { version = "0.6.0", optional = true } +smallvec = "1.6.1" # Uncomment to use local checkout of cranelift #[patch."https://github.com/bytecodealliance/wasmtime/"] @@ -37,6 +38,7 @@ libloading = { version = "0.6.0", optional = true } default = ["jit", "inline_asm"] jit = ["cranelift-jit", "libloading"] inline_asm = [] +oldbe = [] [profile.dev] # By compiling dependencies with optimizations, performing tests gets much faster. diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index 22d9e00923f00..6fa5eebdc2f3d 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -1,6 +1,4 @@ -# WIP Cranelift codegen backend for rust - -> ⚠⚠⚠ Certain kinds of FFI don't work yet. ⚠⚠⚠ +# Cranelift codegen backend for rust The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift). This has the potential to improve compilation times in debug mode. @@ -103,8 +101,7 @@ function jit_calc() { ## Not yet supported -* Good non-rust abi support ([several problems](https://github.com/bjorn3/rustc_codegen_cranelift/issues/10)) -* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041) +* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041)) * On Linux there is support for invoking an external assembler for `global_asm!` and `asm!`. `llvm_asm!` will remain unimplemented forever. `asm!` doesn't yet support reg classes. You have to specify specific registers instead. diff --git a/compiler/rustc_codegen_cranelift/build.sh b/compiler/rustc_codegen_cranelift/build.sh index 26041b59cca18..598ce35eceaac 100755 --- a/compiler/rustc_codegen_cranelift/build.sh +++ b/compiler/rustc_codegen_cranelift/build.sh @@ -3,23 +3,29 @@ set -e # Settings export CHANNEL="release" -build_sysroot=1 +build_sysroot="clif" target_dir='build' +oldbe='' while [[ $# != 0 ]]; do case $1 in "--debug") export CHANNEL="debug" ;; - "--without-sysroot") - build_sysroot=0 + "--sysroot") + build_sysroot=$2 + shift ;; "--target-dir") target_dir=$2 shift ;; + "--oldbe") + oldbe='--features oldbe' + ;; *) echo "Unknown flag '$1'" - echo "Usage: ./build.sh [--debug] [--without-sysroot] [--target-dir DIR]" + echo "Usage: ./build.sh [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--oldbe]" + exit 1 ;; esac shift @@ -27,23 +33,24 @@ done # Build cg_clif unset CARGO_TARGET_DIR -export RUSTFLAGS="-Zrun_dsymutil=no" unamestr=$(uname) if [[ "$unamestr" == 'Linux' ]]; then export RUSTFLAGS='-Clink-arg=-Wl,-rpath=$ORIGIN/../lib '$RUSTFLAGS elif [[ "$unamestr" == 'Darwin' ]]; then - export RUSTFLAGS='-Clink-arg=-Wl,-rpath,@loader_path/../lib -Zosx-rpath-install-name '$RUSTFLAGS + export RUSTFLAGS='-Csplit-debuginfo=unpacked -Clink-arg=-Wl,-rpath,@loader_path/../lib -Zosx-rpath-install-name '$RUSTFLAGS dylib_ext='dylib' else echo "Unsupported os" exit 1 fi if [[ "$CHANNEL" == "release" ]]; then - cargo build --release + cargo build $oldbe --release else - cargo build + cargo build $oldbe fi +source scripts/ext_config.sh + rm -rf "$target_dir" mkdir "$target_dir" mkdir "$target_dir"/bin "$target_dir"/lib @@ -51,10 +58,29 @@ ln target/$CHANNEL/cg_clif{,_build_sysroot} "$target_dir"/bin ln target/$CHANNEL/*rustc_codegen_cranelift* "$target_dir"/lib ln rust-toolchain scripts/config.sh scripts/cargo.sh "$target_dir" -if [[ "$build_sysroot" == "1" ]]; then - echo "[BUILD] sysroot" - export CG_CLIF_INCR_CACHE_DISABLED=1 - dir=$(pwd) - cd "$target_dir" - time "$dir/build_sysroot/build_sysroot.sh" +mkdir -p "$target_dir/lib/rustlib/$TARGET_TRIPLE/lib/" +if [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then + cp $(rustc --print sysroot)/lib/rustlib/$TARGET_TRIPLE/lib/*.o "$target_dir/lib/rustlib/$TARGET_TRIPLE/lib/" fi + +case "$build_sysroot" in + "none") + ;; + "llvm") + cp -r $(rustc --print sysroot)/lib/rustlib/$TARGET_TRIPLE/lib "$target_dir/lib/rustlib/$TARGET_TRIPLE/" + ;; + "clif") + echo "[BUILD] sysroot" + dir=$(pwd) + cd "$target_dir" + time "$dir/build_sysroot/build_sysroot.sh" + cp lib/rustlib/*/lib/libstd-* lib/ + ;; + *) + echo "Unknown sysroot kind \`$build_sysroot\`." + echo "The allowed values are:" + echo " none A sysroot that doesn't contain the standard library" + echo " llvm Copy the sysroot from rustc compiled by cg_llvm" + echo " clif Build a new sysroot using cg_clif" + exit 1 +esac diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index 990557694ead4..0da9999c17285 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -2,9 +2,9 @@ # It is not intended for manual editing. [[package]] name = "addr2line" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" +checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" dependencies = [ "compiler_builtins", "gimli", @@ -63,9 +63,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0782e0a7da7598164153173e5a5d4d9b1da094473c98dce0ff91406112369" +version = "0.1.39" dependencies = [ "rustc-std-workspace-core", ] @@ -130,9 +128,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "compiler_builtins", "libc", @@ -141,9 +139,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.81" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff" dependencies = [ "rustc-std-workspace-core", ] diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml index 3dbd28c286a24..82516c98af2a2 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml @@ -11,12 +11,13 @@ test = { path = "./sysroot_src/library/test" } alloc_system = { path = "./alloc_system" } -compiler_builtins = { version = "=0.1.36", default-features = false } +compiler_builtins = { version = "0.1.39", default-features = false, features = ["no-asm"] } [patch.crates-io] rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" } rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" } rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" } +compiler_builtins = { path = "./compiler-builtins" } [profile.dev] lto = "off" diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh index d7a72df2eb283..282ce4a582c4b 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh @@ -24,17 +24,16 @@ export CARGO_TARGET_DIR=target # Build libs export RUSTFLAGS="$RUSTFLAGS -Zforce-unstable-if-unmarked -Cpanic=abort" +export __CARGO_DEFAULT_LIB_METADATA="cg_clif" if [[ "$1" != "--debug" ]]; then sysroot_channel='release' # FIXME Enable incremental again once rust-lang/rust#74946 is fixed - # FIXME Enable -Zmir-opt-level=2 again once it doesn't ice anymore - CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS" cargo build --target "$TARGET_TRIPLE" --release + CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=2" cargo build --target "$TARGET_TRIPLE" --release else sysroot_channel='debug' cargo build --target "$TARGET_TRIPLE" fi # Copy files to sysroot -mkdir -p "$dir/lib/rustlib/$TARGET_TRIPLE/lib/" ln "target/$TARGET_TRIPLE/$sysroot_channel/deps/"* "$dir/lib/rustlib/$TARGET_TRIPLE/lib/" rm "$dir/lib/rustlib/$TARGET_TRIPLE/lib/"*.{rmeta,d} diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh index 40fbaf646a2f6..d3b87e02ba891 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh @@ -29,4 +29,11 @@ git commit --no-gpg-sign -m "Patch $file" done popd -echo "Successfully prepared libcore for building" +git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned" +pushd compiler-builtins +git checkout -- . +git checkout 0.1.39 +git apply ../../crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch +popd + +echo "Successfully prepared sysroot source for building" diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index 5a69c862d016d..b47efe72bce03 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -1,5 +1,5 @@ #!/bin/bash --verbose set -e -rm -rf target/ build/ build_sysroot/{sysroot_src/,target/} perf.data{,.old} +rm -rf target/ build/ build_sysroot/{sysroot_src/,target/,compiler-builtins/} perf.data{,.old} rm -rf rand/ regex/ simple-raytracer/ diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch new file mode 100644 index 0000000000000..e14768910a9ac --- /dev/null +++ b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch @@ -0,0 +1,35 @@ +From 7078cca3cb614e1e82da428380b4e16fc3afef46 Mon Sep 17 00:00:00 2001 +From: bjorn3 +Date: Thu, 21 Jan 2021 14:46:36 +0100 +Subject: [PATCH] Remove rotate_left from Int + +--- + src/int/mod.rs | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/src/int/mod.rs b/src/int/mod.rs +index 06054c8..3bea17b 100644 +--- a/src/int/mod.rs ++++ b/src/int/mod.rs +@@ -85,7 +85,6 @@ pub trait Int: + fn wrapping_sub(self, other: Self) -> Self; + fn wrapping_shl(self, other: u32) -> Self; + fn wrapping_shr(self, other: u32) -> Self; +- fn rotate_left(self, other: u32) -> Self; + fn overflowing_add(self, other: Self) -> (Self, bool); + fn aborting_div(self, other: Self) -> Self; + fn aborting_rem(self, other: Self) -> Self; +@@ -209,10 +208,6 @@ macro_rules! int_impl_common { + ::wrapping_shr(self, other) + } + +- fn rotate_left(self, other: u32) -> Self { +- ::rotate_left(self, other) +- } +- + fn overflowing_add(self, other: Self) -> (Self, bool) { + ::overflowing_add(self, other) + } +-- +2.26.2.7.g19db9cfb68 + diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs index dc2ad4c676e80..f59600ebb330c 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs @@ -11,7 +11,8 @@ use alloc_system::System; #[global_allocator] static ALLOC: System = System; -#[link(name = "c")] +#[cfg_attr(unix, link(name = "c"))] +#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] extern "C" { fn puts(s: *const u8) -> i32; } diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 10cba99205629..002ec7e2e3d7a 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -532,8 +532,8 @@ pub mod intrinsics { } pub mod libc { - #[cfg_attr(not(windows), link(name = "c"))] - #[cfg_attr(windows, link(name = "msvcrt"))] + #[cfg_attr(unix, link(name = "c"))] + #[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] extern "C" { pub fn puts(s: *const i8) -> i32; pub fn printf(format: *const i8, ...) -> i32; diff --git a/compiler/rustc_codegen_cranelift/example/mod_bench.rs b/compiler/rustc_codegen_cranelift/example/mod_bench.rs index bc65221362346..152041aa9ed0b 100644 --- a/compiler/rustc_codegen_cranelift/example/mod_bench.rs +++ b/compiler/rustc_codegen_cranelift/example/mod_bench.rs @@ -1,7 +1,8 @@ #![feature(start, box_syntax, core_intrinsics, lang_items)] #![no_std] -#[link(name = "c")] +#[cfg_attr(unix, link(name = "c"))] +#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))] extern {} #[panic_handler] diff --git a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch index 8cfffe580a1f0..3eb10069adad6 100644 --- a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch @@ -119,5 +119,21 @@ index 6609bc3..241b497 100644 #[test] #[should_panic(expected = "index 0 greater than length of slice")] +diff --git a/library/core/tests/num/ops.rs b/library/core/tests/num/ops.rs +index 9979cc8..d5d1d83 100644 +--- a/library/core/tests/num/ops.rs ++++ b/library/core/tests/num/ops.rs +@@ -238,7 +238,7 @@ macro_rules! test_shift_assign { + } + }; + } +-test_shift!(test_shl_defined, Shl::shl); +-test_shift_assign!(test_shl_assign_defined, ShlAssign::shl_assign); +-test_shift!(test_shr_defined, Shr::shr); +-test_shift_assign!(test_shr_assign_defined, ShrAssign::shr_assign); ++//test_shift!(test_shl_defined, Shl::shl); ++//test_shift_assign!(test_shl_assign_defined, ShlAssign::shl_assign); ++//test_shift!(test_shr_defined, Shr::shr); ++//test_shift_assign!(test_shr_assign_defined, ShrAssign::shr_assign); -- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index d6ad24bcf26dd..a08f00d19c20f 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1 +1 @@ -nightly-2020-12-23 +nightly-2021-01-30 diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh index dea037e2bc002..834708aa9a6fb 100644 --- a/compiler/rustc_codegen_cranelift/scripts/config.sh +++ b/compiler/rustc_codegen_cranelift/scripts/config.sh @@ -12,28 +12,6 @@ else exit 1 fi -HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") -TARGET_TRIPLE=$HOST_TRIPLE -#TARGET_TRIPLE="x86_64-pc-windows-gnu" -#TARGET_TRIPLE="aarch64-unknown-linux-gnu" - -linker='' -RUN_WRAPPER='' -export JIT_SUPPORTED=1 -if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then - export JIT_SUPPORTED=0 - if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then - # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. - linker='-Clinker=aarch64-linux-gnu-gcc' - RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu' - elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then - # We are cross-compiling for Windows. Run tests in wine. - RUN_WRAPPER='wine' - else - echo "Unknown non-native platform" - fi -fi - if echo "$RUSTC_WRAPPER" | grep sccache; then echo echo -e "\x1b[1;93m=== Warning: Unset RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m" @@ -44,16 +22,14 @@ fi dir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd) export RUSTC=$dir"/bin/cg_clif" -export RUSTFLAGS=$linker" "$RUSTFLAGS + export RUSTDOCFLAGS=$linker' -Cpanic=abort -Zpanic-abort-tests '\ '-Zcodegen-backend='$dir'/lib/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$dir # FIXME remove once the atomic shim is gone -if [[ $(uname) == 'Darwin' ]]; then +if [[ "$unamestr" == 'Darwin' ]]; then export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" fi -export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib" +export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:"$dir"/lib" export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH - -export CG_CLIF_DISPLAY_CG_TIME=1 diff --git a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh new file mode 100644 index 0000000000000..7971f620df14b --- /dev/null +++ b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh @@ -0,0 +1,27 @@ +# Note to people running shellcheck: this file should only be sourced, not executed directly. + +# Various env vars that should only be set for the build system but not for cargo.sh + +set -e + +export CG_CLIF_DISPLAY_CG_TIME=1 +export CG_CLIF_INCR_CACHE_DISABLED=1 + +export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") +export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE} + +export RUN_WRAPPER='' +export JIT_SUPPORTED=1 +if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then + export JIT_SUPPORTED=0 + if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then + # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. + export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS + export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu' + elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then + # We are cross-compiling for Windows. Run tests in wine. + export RUN_WRAPPER='wine' + else + echo "Unknown non-native platform" + fi +fi diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index a61774f479ec7..d37b57babe612 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -3,7 +3,7 @@ set -e source build/config.sh -export CG_CLIF_INCR_CACHE_DISABLED=1 +source scripts/ext_config.sh MY_RUSTC="$RUSTC $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2" function no_sysroot_tests() { diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index 01073d26e832a..9aab45b62e211 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -4,10 +4,10 @@ use std::borrow::Cow; use rustc_middle::mir; +use rustc_target::abi::call::PassMode; use cranelift_codegen::entity::EntityRef; -use crate::abi::pass_mode::*; use crate::prelude::*; pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, impl Module>) { @@ -21,9 +21,9 @@ pub(super) fn add_arg_comment<'tcx>( kind: &str, local: Option, local_field: Option, - params: EmptySinglePair, - pass_mode: PassMode, - ty: Ty<'tcx>, + params: &[Value], + arg_abi_mode: PassMode, + arg_layout: TyAndLayout<'tcx>, ) { let local = if let Some(local) = local { Cow::Owned(format!("{:?}", local)) @@ -37,12 +37,20 @@ pub(super) fn add_arg_comment<'tcx>( }; let params = match params { - Empty => Cow::Borrowed("-"), - Single(param) => Cow::Owned(format!("= {:?}", param)), - Pair(param_a, param_b) => Cow::Owned(format!("= {:?}, {:?}", param_a, param_b)), + [] => Cow::Borrowed("-"), + [param] => Cow::Owned(format!("= {:?}", param)), + [param_a, param_b] => Cow::Owned(format!("= {:?},{:?}", param_a, param_b)), + params => Cow::Owned(format!( + "= {}", + params + .iter() + .map(ToString::to_string) + .collect::>() + .join(",") + )), }; - let pass_mode = format!("{:?}", pass_mode); + let pass_mode = format!("{:?}", arg_abi_mode); fx.add_global_comment(format!( "{kind:5}{local:>3}{local_field:<5} {params:10} {pass_mode:36} {ty:?}", kind = kind, @@ -50,7 +58,7 @@ pub(super) fn add_arg_comment<'tcx>( local_field = local_field, params = params, pass_mode = pass_mode, - ty = ty, + ty = arg_layout.ty, )); } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 76e1987459f87..6a025f2e88ae3 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -6,199 +6,50 @@ mod pass_mode; mod returning; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::ty::layout::FnAbiExt; +use rustc_target::abi::call::{Conv, FnAbi}; use rustc_target::spec::abi::Abi; -use cranelift_codegen::ir::{AbiParam, ArgumentPurpose}; +use cranelift_codegen::ir::AbiParam; +use smallvec::smallvec; use self::pass_mode::*; use crate::prelude::*; pub(crate) use self::returning::{can_return_to_ssa_var, codegen_return}; -// Copied from https://github.com/rust-lang/rust/blob/f52c72948aa1dd718cc1f168d21c91c584c0a662/src/librustc_middle/ty/layout.rs#L2301 -#[rustfmt::skip] -pub(crate) fn fn_sig_for_fn_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::PolyFnSig<'tcx> { - use rustc_middle::ty::subst::Subst; - - // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function. - let ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); - match *ty.kind() { - ty::FnDef(..) => { - // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering - // parameters unused if they show up in the signature, but not in the `mir::Body` - // (i.e. due to being inside a projection that got normalized, see - // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping - // track of a polymorphization `ParamEnv` to allow normalizing later. - let mut sig = match *ty.kind() { - ty::FnDef(def_id, substs) => tcx - .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id)) - .subst(tcx, substs), - _ => unreachable!(), - }; - - if let ty::InstanceDef::VtableShim(..) = instance.def { - // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. - sig = sig.map_bound(|mut sig| { - let mut inputs_and_output = sig.inputs_and_output.to_vec(); - inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]); - sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); - sig - }); - } - sig - } - ty::Closure(def_id, substs) => { - let sig = substs.as_closure().sig(); - - let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); - sig.map_bound(|sig| { - tcx.mk_fn_sig( - std::iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), - sig.output(), - sig.c_variadic, - sig.unsafety, - sig.abi, - ) - }) - } - ty::Generator(_, substs, _) => { - let sig = substs.as_generator().poly_sig(); - - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrEnv }); - let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); - - let pin_did = tcx.require_lang_item(rustc_hir::LangItem::Pin, None); - let pin_adt_ref = tcx.adt_def(pin_did); - let pin_substs = tcx.intern_substs(&[env_ty.into()]); - let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); - - sig.map_bound(|sig| { - let state_did = tcx.require_lang_item(rustc_hir::LangItem::GeneratorState, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = - tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); - - tcx.mk_fn_sig( - [env_ty, sig.resume_ty].iter(), - &ret_ty, - false, - rustc_hir::Unsafety::Normal, - rustc_target::spec::abi::Abi::Rust, - ) - }) - } - _ => bug!("unexpected type {:?} in Instance::fn_sig", ty), - } -} - -fn clif_sig_from_fn_sig<'tcx>( +fn clif_sig_from_fn_abi<'tcx>( tcx: TyCtxt<'tcx>, triple: &target_lexicon::Triple, - sig: FnSig<'tcx>, - span: Span, - is_vtable_fn: bool, - requires_caller_location: bool, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> Signature { - let abi = match sig.abi { - Abi::System => Abi::C, - abi => abi, - }; - let (call_conv, inputs, output): (CallConv, Vec>, Ty<'tcx>) = match abi { - Abi::Rust => ( - CallConv::triple_default(triple), - sig.inputs().to_vec(), - sig.output(), - ), - Abi::C | Abi::Unadjusted => ( - CallConv::triple_default(triple), - sig.inputs().to_vec(), - sig.output(), - ), - Abi::SysV64 => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()), - Abi::RustCall => { - assert_eq!(sig.inputs().len(), 2); - let extra_args = match sig.inputs().last().unwrap().kind() { - ty::Tuple(ref tupled_arguments) => tupled_arguments, - _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"), - }; - let mut inputs: Vec> = vec![sig.inputs()[0]]; - inputs.extend(extra_args.types()); - (CallConv::triple_default(triple), inputs, sig.output()) + let call_conv = match fn_abi.conv { + Conv::Rust | Conv::C => CallConv::triple_default(triple), + Conv::X86_64SysV => CallConv::SystemV, + Conv::X86_64Win64 => CallConv::WindowsFastcall, + Conv::ArmAapcs + | Conv::Msp430Intr + | Conv::PtxKernel + | Conv::X86Fastcall + | Conv::X86Intr + | Conv::X86Stdcall + | Conv::X86ThisCall + | Conv::X86VectorCall + | Conv::AmdGpuKernel + | Conv::AvrInterrupt + | Conv::AvrNonBlockingInterrupt => { + todo!("{:?}", fn_abi.conv) } - Abi::System => unreachable!(), - Abi::RustIntrinsic => ( - CallConv::triple_default(triple), - sig.inputs().to_vec(), - sig.output(), - ), - _ => unimplemented!("unsupported abi {:?}", sig.abi), }; - - let inputs = inputs - .into_iter() - .enumerate() - .map(|(i, ty)| { - let mut layout = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap(); - if i == 0 && is_vtable_fn { - // Virtual calls turn their self param into a thin pointer. - // See https://github.com/rust-lang/rust/blob/37b6a5e5e82497caf5353d9d856e4eb5d14cbe06/src/librustc/ty/layout.rs#L2519-L2572 for more info - layout = tcx - .layout_of(ParamEnv::reveal_all().and(tcx.mk_mut_ptr(tcx.mk_unit()))) - .unwrap(); - } - let pass_mode = get_pass_mode(tcx, layout); - if abi != Abi::Rust && abi != Abi::RustCall && abi != Abi::RustIntrinsic { - match pass_mode { - PassMode::NoPass | PassMode::ByVal(_) => {} - PassMode::ByRef { size: Some(size) } => { - let purpose = ArgumentPurpose::StructArgument(u32::try_from(size.bytes()).expect("struct too big to pass on stack")); - return EmptySinglePair::Single(AbiParam::special(pointer_ty(tcx), purpose)).into_iter(); - } - PassMode::ByValPair(_, _) | PassMode::ByRef { size: None } => { - tcx.sess.span_warn( - span, - &format!( - "Argument of type `{:?}` with pass mode `{:?}` is not yet supported \ - for non-rust abi `{}`. Calling this function may result in a crash.", - layout.ty, - pass_mode, - abi, - ), - ); - } - } - } - pass_mode.get_param_ty(tcx).map(AbiParam::new).into_iter() - }) + let inputs = fn_abi + .args + .iter() + .map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()) .flatten(); - let (mut params, returns): (Vec<_>, Vec<_>) = match get_pass_mode( - tcx, - tcx.layout_of(ParamEnv::reveal_all().and(output)).unwrap(), - ) { - PassMode::NoPass => (inputs.collect(), vec![]), - PassMode::ByVal(ret_ty) => (inputs.collect(), vec![AbiParam::new(ret_ty)]), - PassMode::ByValPair(ret_ty_a, ret_ty_b) => ( - inputs.collect(), - vec![AbiParam::new(ret_ty_a), AbiParam::new(ret_ty_b)], - ), - PassMode::ByRef { size: Some(_) } => { - ( - Some(pointer_ty(tcx)) // First param is place to put return val - .into_iter() - .map(|ty| AbiParam::special(ty, ArgumentPurpose::StructReturn)) - .chain(inputs) - .collect(), - vec![], - ) - } - PassMode::ByRef { size: None } => todo!(), - }; - - if requires_caller_location { - params.push(AbiParam::new(pointer_ty(tcx))); - } + let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx); + // Sometimes the first param is an pointer to the place where the return value needs to be stored. + let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect(); Signature { params, @@ -207,30 +58,17 @@ fn clif_sig_from_fn_sig<'tcx>( } } -pub(crate) fn get_function_name_and_sig<'tcx>( +pub(crate) fn get_function_sig<'tcx>( tcx: TyCtxt<'tcx>, triple: &target_lexicon::Triple, inst: Instance<'tcx>, - support_vararg: bool, -) -> (String, Signature) { +) -> Signature { assert!(!inst.substs.needs_infer()); - let fn_sig = tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_sig_for_fn_abi(tcx, inst)); - if fn_sig.c_variadic && !support_vararg { - tcx.sess.span_fatal( - tcx.def_span(inst.def_id()), - "Variadic function definitions are not yet supported", - ); - } - let sig = clif_sig_from_fn_sig( + clif_sig_from_fn_abi( tcx, triple, - fn_sig, - tcx.def_span(inst.def_id()), - false, - inst.def.requires_caller_location(tcx), - ); - (tcx.symbol_name(inst).name.to_string(), sig) + &FnAbi::of_instance(&RevealAllLayoutCx(tcx), inst, &[]), + ) } /// Instance must be monomorphized @@ -239,7 +77,8 @@ pub(crate) fn import_function<'tcx>( module: &mut impl Module, inst: Instance<'tcx>, ) -> FuncId { - let (name, sig) = get_function_name_and_sig(tcx, module.isa().triple(), inst, true); + let name = tcx.symbol_name(inst).name.to_string(); + let sig = get_function_sig(tcx, module.isa().triple(), inst); module .declare_function(&name, Linkage::Import, &sig) .unwrap() @@ -263,13 +102,13 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { pub(crate) fn lib_call( &mut self, name: &str, - input_tys: Vec, - output_tys: Vec, + params: Vec, + returns: Vec, args: &[Value], ) -> &[Value] { let sig = Signature { - params: input_tys.iter().cloned().map(AbiParam::new).collect(), - returns: output_tys.iter().cloned().map(AbiParam::new).collect(), + params, + returns, call_conv: CallConv::triple_default(self.triple()), }; let func_id = self @@ -301,16 +140,18 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { .iter() .map(|arg| { ( - self.clif_type(arg.layout().ty).unwrap(), + AbiParam::new(self.clif_type(arg.layout().ty).unwrap()), arg.load_scalar(self), ) }) .unzip(); let return_layout = self.layout_of(return_ty); let return_tys = if let ty::Tuple(tup) = return_ty.kind() { - tup.types().map(|ty| self.clif_type(ty).unwrap()).collect() + tup.types() + .map(|ty| AbiParam::new(self.clif_type(ty).unwrap())) + .collect() } else { - vec![self.clif_type(return_ty).unwrap()] + vec![AbiParam::new(self.clif_type(return_ty).unwrap())] }; let ret_vals = self.lib_call(name, input_tys, return_tys, &args); match *ret_vals { @@ -352,12 +193,25 @@ pub(crate) fn codegen_fn_prelude<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, start_block: Block, ) { + fx.bcx.append_block_params_for_function_params(start_block); + + fx.bcx.switch_to_block(start_block); + fx.bcx.ins().nop(); + let ssa_analyzed = crate::analyze::analyze(fx); #[cfg(debug_assertions)] self::comments::add_args_header_comment(fx); - let ret_place = self::returning::codegen_return_param(fx, &ssa_analyzed, start_block); + let mut block_params_iter = fx + .bcx + .func + .dfg + .block_params(start_block) + .to_vec() + .into_iter(); + let ret_place = + self::returning::codegen_return_param(fx, &ssa_analyzed, &mut block_params_iter); assert_eq!(fx.local_map.push(ret_place), RETURN_PLACE); // None means pass_mode == NoPass @@ -366,6 +220,9 @@ pub(crate) fn codegen_fn_prelude<'tcx>( Spread(Vec>>), } + let fn_abi = fx.fn_abi.take().unwrap(); + let mut arg_abis_iter = fn_abi.args.iter(); + let func_params = fx .mir .args_iter() @@ -385,14 +242,18 @@ pub(crate) fn codegen_fn_prelude<'tcx>( }; let mut params = Vec::new(); - for (i, arg_ty) in tupled_arg_tys.types().enumerate() { - let param = cvalue_for_param(fx, start_block, Some(local), Some(i), arg_ty); + for (i, _arg_ty) in tupled_arg_tys.types().enumerate() { + let arg_abi = arg_abis_iter.next().unwrap(); + let param = + cvalue_for_param(fx, Some(local), Some(i), arg_abi, &mut block_params_iter); params.push(param); } (local, ArgKind::Spread(params), arg_ty) } else { - let param = cvalue_for_param(fx, start_block, Some(local), None, arg_ty); + let arg_abi = arg_abis_iter.next().unwrap(); + let param = + cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter); (local, ArgKind::Normal(param), arg_ty) } }) @@ -401,13 +262,14 @@ pub(crate) fn codegen_fn_prelude<'tcx>( assert!(fx.caller_location.is_none()); if fx.instance.def.requires_caller_location(fx.tcx) { // Store caller location for `#[track_caller]`. - fx.caller_location = Some( - cvalue_for_param(fx, start_block, None, None, fx.tcx.caller_location_ty()).unwrap(), - ); + let arg_abi = arg_abis_iter.next().unwrap(); + fx.caller_location = + Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap()); } - fx.bcx.switch_to_block(start_block); - fx.bcx.ins().nop(); + assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind"); + fx.fn_abi = Some(fn_abi); + assert!(block_params_iter.next().is_none(), "arg_value left behind"); #[cfg(debug_assertions)] self::comments::add_locals_header_comment(fx); @@ -533,6 +395,21 @@ pub(crate) fn codegen_terminator_call<'tcx>( None }; + let extra_args = &args[fn_sig.inputs().len()..]; + let extra_args = extra_args + .iter() + .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))) + .collect::>(); + let fn_abi = if let Some(instance) = instance { + FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args) + } else { + FnAbi::of_fn_ptr( + &RevealAllLayoutCx(fx.tcx), + fn_ty.fn_sig(fx.tcx), + &extra_args, + ) + }; + let is_cold = instance .map(|inst| { fx.tcx @@ -570,8 +447,8 @@ pub(crate) fn codegen_terminator_call<'tcx>( // | indirect call target // | | the first argument to be passed - // v v v virtual calls are special cased below - let (func_ref, first_arg, is_virtual_call) = match instance { + // v v + let (func_ref, first_arg) = match instance { // Trait object call Some(Instance { def: InstanceDef::Virtual(_, idx), @@ -582,23 +459,19 @@ pub(crate) fn codegen_terminator_call<'tcx>( let nop_inst = fx.bcx.ins().nop(); fx.add_comment( nop_inst, - format!( - "virtual call; self arg pass mode: {:?}", - get_pass_mode(fx.tcx, args[0].layout()) - ), + format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0],), ); } let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx); - (Some(method), Single(ptr), true) + (Some(method), smallvec![ptr]) } // Normal call Some(_) => ( None, args.get(0) - .map(|arg| adjust_arg_for_abi(fx, *arg)) - .unwrap_or(Empty), - false, + .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0])) + .unwrap_or(smallvec![]), ), // Indirect call @@ -612,23 +485,27 @@ pub(crate) fn codegen_terminator_call<'tcx>( ( Some(func), args.get(0) - .map(|arg| adjust_arg_for_abi(fx, *arg)) - .unwrap_or(Empty), - false, + .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0])) + .unwrap_or(smallvec![]), ) } }; let ret_place = destination.map(|(place, _)| place); - let (call_inst, call_args) = - self::returning::codegen_with_call_return_arg(fx, fn_sig, ret_place, |fx, return_ptr| { + let (call_inst, call_args) = self::returning::codegen_with_call_return_arg( + fx, + &fn_abi.ret, + ret_place, + |fx, return_ptr| { + let regular_args_count = args.len(); let mut call_args: Vec = return_ptr .into_iter() .chain(first_arg.into_iter()) .chain( args.into_iter() + .enumerate() .skip(1) - .map(|arg| adjust_arg_for_abi(fx, arg).into_iter()) + .map(|(i, arg)| adjust_arg_for_abi(fx, arg, &fn_abi.args[i]).into_iter()) .flatten(), ) .collect::>(); @@ -639,18 +516,17 @@ pub(crate) fn codegen_terminator_call<'tcx>( { // Pass the caller location for `#[track_caller]`. let caller_location = fx.get_caller_location(span); - call_args.extend(adjust_arg_for_abi(fx, caller_location).into_iter()); + call_args.extend( + adjust_arg_for_abi(fx, caller_location, &fn_abi.args[regular_args_count]) + .into_iter(), + ); + assert_eq!(fn_abi.args.len(), regular_args_count + 1); + } else { + assert_eq!(fn_abi.args.len(), regular_args_count); } let call_inst = if let Some(func_ref) = func_ref { - let sig = clif_sig_from_fn_sig( - fx.tcx, - fx.triple(), - fn_sig, - span, - is_virtual_call, - false, // calls through function pointers never pass the caller location - ); + let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi); let sig = fx.bcx.import_signature(sig); fx.bcx.ins().call_indirect(sig, func_ref, &call_args) } else { @@ -660,7 +536,8 @@ pub(crate) fn codegen_terminator_call<'tcx>( }; (call_inst, call_args) - }); + }, + ); // FIXME find a cleaner way to support varargs if fn_sig.c_variadic { @@ -701,37 +578,33 @@ pub(crate) fn codegen_drop<'tcx>( drop_place: CPlace<'tcx>, ) { let ty = drop_place.layout().ty; - let drop_fn = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); + let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); - if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { + if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def { // we don't actually need to drop anything } else { - let drop_fn_ty = drop_fn.ty(fx.tcx, ParamEnv::reveal_all()); - let fn_sig = fx.tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - drop_fn_ty.fn_sig(fx.tcx), - ); - assert_eq!(fn_sig.output(), fx.tcx.mk_unit()); - match ty.kind() { ty::Dynamic(..) => { let (ptr, vtable) = drop_place.to_ptr_maybe_unsized(); let ptr = ptr.get_addr(fx); let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap()); - let sig = clif_sig_from_fn_sig( - fx.tcx, - fx.triple(), - fn_sig, - span, - true, - false, // `drop_in_place` is never `#[track_caller]` - ); + // FIXME(eddyb) perhaps move some of this logic into + // `Instance::resolve_drop_in_place`? + let virtual_drop = Instance { + def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), + substs: drop_instance.substs, + }; + let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), virtual_drop, &[]); + + let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi); let sig = fx.bcx.import_signature(sig); fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]); } _ => { - assert!(!matches!(drop_fn.def, InstanceDef::Virtual(_, _))); + assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _))); + + let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), drop_instance, &[]); let arg_value = drop_place.place_ref( fx, @@ -743,17 +616,19 @@ pub(crate) fn codegen_drop<'tcx>( }, )), ); - let arg_value = adjust_arg_for_abi(fx, arg_value); + let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0]); let mut call_args: Vec = arg_value.into_iter().collect::>(); - if drop_fn.def.requires_caller_location(fx.tcx) { + if drop_instance.def.requires_caller_location(fx.tcx) { // Pass the caller location for `#[track_caller]`. let caller_location = fx.get_caller_location(span); - call_args.extend(adjust_arg_for_abi(fx, caller_location).into_iter()); + call_args.extend( + adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1]).into_iter(), + ); } - let func_ref = fx.get_function_ref(drop_fn); + let func_ref = fx.get_function_ref(drop_instance); fx.bcx.ins().call(func_ref, &call_args); } } diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 8e3682c86c5fb..1202c23dbe7b3 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -1,140 +1,281 @@ //! Argument passing use crate::prelude::*; +use crate::value_and_place::assert_assignable; -pub(super) use EmptySinglePair::*; +use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose}; +use rustc_target::abi::call::{ + ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind, +}; +use smallvec::{smallvec, SmallVec}; -#[derive(Copy, Clone, Debug)] -pub(super) enum PassMode { - NoPass, - ByVal(Type), - ByValPair(Type, Type), - ByRef { size: Option }, +pub(super) trait ArgAbiExt<'tcx> { + fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>; + fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option, Vec); } -#[derive(Copy, Clone, Debug)] -pub(super) enum EmptySinglePair { - Empty, - Single(T), - Pair(T, T), +fn reg_to_abi_param(reg: Reg) -> AbiParam { + let clif_ty = match (reg.kind, reg.size.bytes()) { + (RegKind::Integer, 1) => types::I8, + (RegKind::Integer, 2) => types::I16, + (RegKind::Integer, 4) => types::I32, + (RegKind::Integer, 8) => types::I64, + (RegKind::Integer, 16) => types::I128, + (RegKind::Float, 4) => types::F32, + (RegKind::Float, 8) => types::F64, + (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(), + _ => unreachable!("{:?}", reg), + }; + AbiParam::new(clif_ty) } -impl EmptySinglePair { - pub(super) fn into_iter(self) -> EmptySinglePairIter { - EmptySinglePairIter(self) - } - - pub(super) fn map(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair { - match self { - Empty => Empty, - Single(v) => Single(f(v)), - Pair(a, b) => Pair(f(a), f(b)), - } +fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam { + match arg_attrs.arg_ext { + RustcArgExtension::None => {} + RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext, + RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext, } + param } -pub(super) struct EmptySinglePairIter(EmptySinglePair); - -impl Iterator for EmptySinglePairIter { - type Item = T; +fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> { + let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 { + (0, 0) + } else { + ( + cast.rest.total.bytes() / cast.rest.unit.size.bytes(), + cast.rest.total.bytes() % cast.rest.unit.size.bytes(), + ) + }; - fn next(&mut self) -> Option { - match std::mem::replace(&mut self.0, Empty) { - Empty => None, - Single(v) => Some(v), - Pair(a, b) => { - self.0 = Single(b); - Some(a) - } + if cast.prefix.iter().all(|x| x.is_none()) { + // Simplify to a single unit when there is no prefix and size <= unit size + if cast.rest.total <= cast.rest.unit.size { + let clif_ty = match (cast.rest.unit.kind, cast.rest.unit.size.bytes()) { + (RegKind::Integer, 1) => types::I8, + (RegKind::Integer, 2) => types::I16, + (RegKind::Integer, 3..=4) => types::I32, + (RegKind::Integer, 5..=8) => types::I64, + (RegKind::Integer, 9..=16) => types::I128, + (RegKind::Float, 4) => types::F32, + (RegKind::Float, 8) => types::F64, + (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(), + _ => unreachable!("{:?}", cast.rest.unit), + }; + return smallvec![AbiParam::new(clif_ty)]; } } -} -impl EmptySinglePair { - pub(super) fn assert_single(self) -> T { - match self { - Single(v) => v, - _ => panic!("Called assert_single on {:?}", self), - } - } + // Create list of fields in the main structure + let mut args = cast + .prefix + .iter() + .flatten() + .map(|&kind| { + reg_to_abi_param(Reg { + kind, + size: cast.prefix_chunk_size, + }) + }) + .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit))) + .collect::>(); - pub(super) fn assert_pair(self) -> (T, T) { - match self { - Pair(a, b) => (a, b), - _ => panic!("Called assert_pair on {:?}", self), - } + // Append final integer + if rem_bytes != 0 { + // Only integers can be really split further. + assert_eq!(cast.rest.unit.kind, RegKind::Integer); + args.push(reg_to_abi_param(Reg { + kind: RegKind::Integer, + size: Size::from_bytes(rem_bytes), + })); } -} -impl PassMode { - pub(super) fn get_param_ty(self, tcx: TyCtxt<'_>) -> EmptySinglePair { - match self { - PassMode::NoPass => Empty, - PassMode::ByVal(clif_type) => Single(clif_type), - PassMode::ByValPair(a, b) => Pair(a, b), - PassMode::ByRef { size: Some(_) } => Single(pointer_ty(tcx)), - PassMode::ByRef { size: None } => Pair(pointer_ty(tcx), pointer_ty(tcx)), - } - } + args } -pub(super) fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> PassMode { - if layout.is_zst() { - // WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer - PassMode::NoPass - } else { - match &layout.abi { - Abi::Uninhabited => PassMode::NoPass, - Abi::Scalar(scalar) => PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone())), - Abi::ScalarPair(a, b) => { - let a = scalar_to_clif_type(tcx, a.clone()); - let b = scalar_to_clif_type(tcx, b.clone()); - if a == types::I128 && b == types::I128 { - // Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are - // available on x86_64. Cranelift gets confused when too many return params - // are used. - PassMode::ByRef { - size: Some(layout.size), - } - } else { - PassMode::ByValPair(a, b) +impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { + fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> { + match self.mode { + PassMode::Ignore => smallvec![], + PassMode::Direct(attrs) => match &self.layout.abi { + Abi::Scalar(scalar) => { + smallvec![apply_arg_attrs_to_abi_param( + AbiParam::new(scalar_to_clif_type(tcx, scalar.clone())), + attrs + )] } - } - - // FIXME implement Vector Abi in a cg_llvm compatible way - Abi::Vector { .. } => { - if let Some(vector_ty) = crate::intrinsics::clif_vector_type(tcx, layout) { - PassMode::ByVal(vector_ty) + Abi::Vector { .. } => { + let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap(); + smallvec![AbiParam::new(vector_ty)] + } + _ => unreachable!("{:?}", self.layout.abi), + }, + PassMode::Pair(attrs_a, attrs_b) => match &self.layout.abi { + Abi::ScalarPair(a, b) => { + let a = scalar_to_clif_type(tcx, a.clone()); + let b = scalar_to_clif_type(tcx, b.clone()); + smallvec![ + apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a), + apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b), + ] + } + _ => unreachable!("{:?}", self.layout.abi), + }, + PassMode::Cast(cast) => cast_target_to_abi_params(cast), + PassMode::Indirect { + attrs, + extra_attrs: None, + on_stack, + } => { + if on_stack { + let size = u32::try_from(self.layout.size.bytes()).unwrap(); + smallvec![apply_arg_attrs_to_abi_param( + AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),), + attrs + )] } else { - PassMode::ByRef { - size: Some(layout.size), - } + smallvec![apply_arg_attrs_to_abi_param( + AbiParam::new(pointer_ty(tcx)), + attrs + )] } } + PassMode::Indirect { + attrs, + extra_attrs: Some(extra_attrs), + on_stack, + } => { + assert!(!on_stack); + smallvec![ + apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), + apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), extra_attrs), + ] + } + } + } - Abi::Aggregate { sized: true } => PassMode::ByRef { - size: Some(layout.size), + fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option, Vec) { + match self.mode { + PassMode::Ignore => (None, vec![]), + PassMode::Direct(_) => match &self.layout.abi { + Abi::Scalar(scalar) => ( + None, + vec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))], + ), + Abi::Vector { .. } => { + let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap(); + (None, vec![AbiParam::new(vector_ty)]) + } + _ => unreachable!("{:?}", self.layout.abi), + }, + PassMode::Pair(_, _) => match &self.layout.abi { + Abi::ScalarPair(a, b) => { + let a = scalar_to_clif_type(tcx, a.clone()); + let b = scalar_to_clif_type(tcx, b.clone()); + (None, vec![AbiParam::new(a), AbiParam::new(b)]) + } + _ => unreachable!("{:?}", self.layout.abi), }, - Abi::Aggregate { sized: false } => PassMode::ByRef { size: None }, + PassMode::Cast(cast) => (None, cast_target_to_abi_params(cast).into_iter().collect()), + PassMode::Indirect { + attrs: _, + extra_attrs: None, + on_stack, + } => { + assert!(!on_stack); + ( + Some(AbiParam::special( + pointer_ty(tcx), + ArgumentPurpose::StructReturn, + )), + vec![], + ) + } + PassMode::Indirect { + attrs: _, + extra_attrs: Some(_), + on_stack: _, + } => unreachable!("unsized return value"), } } } +pub(super) fn to_casted_value<'tcx>( + fx: &mut FunctionCx<'_, 'tcx, impl Module>, + arg: CValue<'tcx>, + cast: CastTarget, +) -> SmallVec<[Value; 2]> { + let (ptr, meta) = arg.force_stack(fx); + assert!(meta.is_none()); + let mut offset = 0; + cast_target_to_abi_params(cast) + .into_iter() + .map(|param| { + let val = ptr + .offset_i64(fx, offset) + .load(fx, param.value_type, MemFlags::new()); + offset += i64::from(param.value_type.bytes()); + val + }) + .collect() +} + +pub(super) fn from_casted_value<'tcx>( + fx: &mut FunctionCx<'_, 'tcx, impl Module>, + block_params: &[Value], + layout: TyAndLayout<'tcx>, + cast: CastTarget, +) -> CValue<'tcx> { + let abi_params = cast_target_to_abi_params(cast); + let abi_param_size: u32 = abi_params + .iter() + .map(|param| param.value_type.bytes()) + .sum(); + let layout_size = u32::try_from(layout.size.bytes()).unwrap(); + let stack_slot = fx.bcx.create_stack_slot(StackSlotData { + kind: StackSlotKind::ExplicitSlot, + // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to + // specify stack slot alignment. + // Stack slot size may be bigger for for example `[u8; 3]` which is packed into an `i32`. + // It may also be smaller for example when the type is a wrapper around an integer with a + // larger alignment than the integer. + size: (std::cmp::max(abi_param_size, layout_size) + 15) / 16 * 16, + offset: None, + }); + let ptr = Pointer::new(fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0)); + let mut offset = 0; + let mut block_params_iter = block_params.into_iter().copied(); + for param in abi_params { + let val = ptr.offset_i64(fx, offset).store( + fx, + block_params_iter.next().unwrap(), + MemFlags::new(), + ); + offset += i64::from(param.value_type.bytes()); + val + } + assert_eq!(block_params_iter.next(), None, "Leftover block param"); + CValue::by_ref(ptr, layout) +} + /// Get a set of values to be passed as function arguments. pub(super) fn adjust_arg_for_abi<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, arg: CValue<'tcx>, -) -> EmptySinglePair { - match get_pass_mode(fx.tcx, arg.layout()) { - PassMode::NoPass => Empty, - PassMode::ByVal(_) => Single(arg.load_scalar(fx)), - PassMode::ByValPair(_, _) => { + arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, +) -> SmallVec<[Value; 2]> { + assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty); + match arg_abi.mode { + PassMode::Ignore => smallvec![], + PassMode::Direct(_) => smallvec![arg.load_scalar(fx)], + PassMode::Pair(_, _) => { let (a, b) = arg.load_scalar_pair(fx); - Pair(a, b) + smallvec![a, b] } - PassMode::ByRef { size: _ } => match arg.force_stack(fx) { - (ptr, None) => Single(ptr.get_addr(fx)), - (ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta), + PassMode::Cast(cast) => to_casted_value(fx, arg, cast), + PassMode::Indirect { .. } => match arg.force_stack(fx) { + (ptr, None) => smallvec![ptr.get_addr(fx)], + (ptr, Some(meta)) => smallvec![ptr.get_addr(fx), meta], }, } } @@ -143,20 +284,23 @@ pub(super) fn adjust_arg_for_abi<'tcx>( /// as necessary. pub(super) fn cvalue_for_param<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, - start_block: Block, #[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option, #[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option, - arg_ty: Ty<'tcx>, + arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, + block_params_iter: &mut impl Iterator, ) -> Option> { - let layout = fx.layout_of(arg_ty); - let pass_mode = get_pass_mode(fx.tcx, layout); - - if let PassMode::NoPass = pass_mode { - return None; - } - - let clif_types = pass_mode.get_param_ty(fx.tcx); - let block_params = clif_types.map(|t| fx.bcx.append_block_param(start_block, t)); + let block_params = arg_abi + .get_abi_param(fx.tcx) + .into_iter() + .map(|abi_param| { + let block_param = block_params_iter.next().unwrap(); + assert_eq!( + fx.bcx.func.dfg.value_type(block_param), + abi_param.value_type + ); + block_param + }) + .collect::>(); #[cfg(debug_assertions)] crate::abi::comments::add_arg_comment( @@ -164,25 +308,48 @@ pub(super) fn cvalue_for_param<'tcx>( "arg", local, local_field, - block_params, - pass_mode, - arg_ty, + &block_params, + arg_abi.mode, + arg_abi.layout, ); - match pass_mode { - PassMode::NoPass => unreachable!(), - PassMode::ByVal(_) => Some(CValue::by_val(block_params.assert_single(), layout)), - PassMode::ByValPair(_, _) => { - let (a, b) = block_params.assert_pair(); - Some(CValue::by_val_pair(a, b, layout)) + match arg_abi.mode { + PassMode::Ignore => None, + PassMode::Direct(_) => { + assert_eq!(block_params.len(), 1, "{:?}", block_params); + Some(CValue::by_val(block_params[0], arg_abi.layout)) + } + PassMode::Pair(_, _) => { + assert_eq!(block_params.len(), 2, "{:?}", block_params); + Some(CValue::by_val_pair( + block_params[0], + block_params[1], + arg_abi.layout, + )) + } + PassMode::Cast(cast) => Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)), + PassMode::Indirect { + attrs: _, + extra_attrs: None, + on_stack: _, + } => { + assert_eq!(block_params.len(), 1, "{:?}", block_params); + Some(CValue::by_ref( + Pointer::new(block_params[0]), + arg_abi.layout, + )) } - PassMode::ByRef { size: Some(_) } => Some(CValue::by_ref( - Pointer::new(block_params.assert_single()), - layout, - )), - PassMode::ByRef { size: None } => { - let (ptr, meta) = block_params.assert_pair(); - Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout)) + PassMode::Indirect { + attrs: _, + extra_attrs: Some(_), + on_stack: _, + } => { + assert_eq!(block_params.len(), 2, "{:?}", block_params); + Some(CValue::by_ref_unsized( + Pointer::new(block_params[0]), + block_params[1], + arg_abi.layout, + )) } } } diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index f6d40c880d094..a382963bf1ed7 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -1,21 +1,57 @@ //! Return value handling -use crate::abi::pass_mode::*; use crate::prelude::*; -fn return_layout<'a, 'tcx>(fx: &mut FunctionCx<'a, 'tcx, impl Module>) -> TyAndLayout<'tcx> { - fx.layout_of(fx.monomorphize(&fx.mir.local_decls[RETURN_PLACE].ty)) -} +use rustc_middle::ty::layout::FnAbiExt; +use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use smallvec::{smallvec, SmallVec}; /// Can the given type be returned into an ssa var or does it need to be returned on the stack. pub(crate) fn can_return_to_ssa_var<'tcx>( - tcx: TyCtxt<'tcx>, - dest_layout: TyAndLayout<'tcx>, + fx: &FunctionCx<'_, 'tcx, impl Module>, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], ) -> bool { - match get_pass_mode(tcx, dest_layout) { - PassMode::NoPass | PassMode::ByVal(_) | PassMode::ByValPair(_, _) => true, - // FIXME Make it possible to return ByRef to an ssa var. - PassMode::ByRef { size: _ } => false, + 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)); + + // Handle special calls like instrinsics and empty drop glue. + let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() { + let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs) + .unwrap() + .unwrap() + .polymorphize(fx.tcx); + + match instance.def { + InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => { + return true; + } + _ => Some(instance), + } + } else { + None + }; + + let extra_args = &args[fn_sig.inputs().len()..]; + let extra_args = extra_args + .iter() + .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))) + .collect::>(); + let fn_abi = if let Some(instance) = instance { + FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args) + } else { + FnAbi::of_fn_ptr( + &RevealAllLayoutCx(fx.tcx), + fn_ty.fn_sig(fx.tcx), + &extra_args, + ) + }; + match fn_abi.ret.mode { + PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) => true, + // FIXME Make it possible to return Cast and Indirect to an ssa var. + PassMode::Cast(_) | PassMode::Indirect { .. } => false, } } @@ -24,27 +60,45 @@ pub(crate) fn can_return_to_ssa_var<'tcx>( pub(super) fn codegen_return_param<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, ssa_analyzed: &rustc_index::vec::IndexVec, - start_block: Block, + block_params_iter: &mut impl Iterator, ) -> CPlace<'tcx> { - let ret_layout = return_layout(fx); - let ret_pass_mode = get_pass_mode(fx.tcx, ret_layout); - let (ret_place, ret_param) = match ret_pass_mode { - PassMode::NoPass => (CPlace::no_place(ret_layout), Empty), - PassMode::ByVal(_) | PassMode::ByValPair(_, _) => { + let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode { + PassMode::Ignore => ( + CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout), + smallvec![], + ), + PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => { let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa; ( - super::make_local_place(fx, RETURN_PLACE, ret_layout, is_ssa), - Empty, + super::make_local_place( + fx, + RETURN_PLACE, + fx.fn_abi.as_ref().unwrap().ret.layout, + is_ssa, + ), + smallvec![], ) } - PassMode::ByRef { size: Some(_) } => { - let ret_param = fx.bcx.append_block_param(start_block, fx.pointer_type); + PassMode::Indirect { + attrs: _, + extra_attrs: None, + on_stack: _, + } => { + let ret_param = block_params_iter.next().unwrap(); + assert_eq!(fx.bcx.func.dfg.value_type(ret_param), pointer_ty(fx.tcx)); ( - CPlace::for_ptr(Pointer::new(ret_param), ret_layout), - Single(ret_param), + CPlace::for_ptr( + Pointer::new(ret_param), + fx.fn_abi.as_ref().unwrap().ret.layout, + ), + smallvec![ret_param], ) } - PassMode::ByRef { size: None } => todo!(), + PassMode::Indirect { + attrs: _, + extra_attrs: Some(_), + on_stack: _, + } => unreachable!("unsized return value"), }; #[cfg(not(debug_assertions))] @@ -56,9 +110,9 @@ pub(super) fn codegen_return_param<'tcx>( "ret", Some(RETURN_PLACE), None, - ret_param, - ret_pass_mode, - ret_layout.ty, + &ret_param, + fx.fn_abi.as_ref().unwrap().ret.mode, + fx.fn_abi.as_ref().unwrap().ret.layout, ); ret_place @@ -68,42 +122,71 @@ pub(super) fn codegen_return_param<'tcx>( /// returns the call return value(s) if any are written to the correct place. pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>( fx: &mut FunctionCx<'_, 'tcx, M>, - fn_sig: FnSig<'tcx>, + ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, ret_place: Option>, f: impl FnOnce(&mut FunctionCx<'_, 'tcx, M>, Option) -> (Inst, T), ) -> (Inst, T) { - let ret_layout = fx.layout_of(fn_sig.output()); - - let output_pass_mode = get_pass_mode(fx.tcx, ret_layout); - let return_ptr = match output_pass_mode { - PassMode::NoPass => None, - PassMode::ByRef { size: Some(_) } => match ret_place { + let return_ptr = match ret_arg_abi.mode { + PassMode::Ignore => None, + PassMode::Indirect { + attrs: _, + extra_attrs: None, + on_stack: _, + } => match ret_place { Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)), None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot }, - PassMode::ByRef { size: None } => todo!(), - PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None, + PassMode::Indirect { + attrs: _, + extra_attrs: Some(_), + on_stack: _, + } => unreachable!("unsized return value"), + PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None, }; let (call_inst, meta) = f(fx, return_ptr); - match output_pass_mode { - PassMode::NoPass => {} - PassMode::ByVal(_) => { + match ret_arg_abi.mode { + PassMode::Ignore => {} + PassMode::Direct(_) => { if let Some(ret_place) = ret_place { let ret_val = fx.bcx.inst_results(call_inst)[0]; - ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_layout)); + ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout)); } } - PassMode::ByValPair(_, _) => { + PassMode::Pair(_, _) => { if let Some(ret_place) = ret_place { let ret_val_a = fx.bcx.inst_results(call_inst)[0]; let ret_val_b = fx.bcx.inst_results(call_inst)[1]; - ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout)); + ret_place.write_cvalue( + fx, + CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout), + ); } } - PassMode::ByRef { size: Some(_) } => {} - PassMode::ByRef { size: None } => todo!(), + PassMode::Cast(cast) => { + if let Some(ret_place) = ret_place { + let results = fx + .bcx + .inst_results(call_inst) + .into_iter() + .copied() + .collect::>(); + let result = + super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); + ret_place.write_cvalue(fx, result); + } + } + PassMode::Indirect { + attrs: _, + extra_attrs: None, + on_stack: _, + } => {} + PassMode::Indirect { + attrs: _, + extra_attrs: Some(_), + on_stack: _, + } => unreachable!("unsized return value"), } (call_inst, meta) @@ -111,20 +194,35 @@ pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>( /// Codegen a return instruction with the right return value(s) if any. pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, impl Module>) { - match get_pass_mode(fx.tcx, return_layout(fx)) { - PassMode::NoPass | PassMode::ByRef { size: Some(_) } => { + match fx.fn_abi.as_ref().unwrap().ret.mode { + PassMode::Ignore + | PassMode::Indirect { + attrs: _, + extra_attrs: None, + on_stack: _, + } => { fx.bcx.ins().return_(&[]); } - PassMode::ByRef { size: None } => todo!(), - PassMode::ByVal(_) => { + PassMode::Indirect { + attrs: _, + extra_attrs: Some(_), + on_stack: _, + } => unreachable!("unsized return value"), + PassMode::Direct(_) => { let place = fx.get_local_place(RETURN_PLACE); let ret_val = place.to_cvalue(fx).load_scalar(fx); fx.bcx.ins().return_(&[ret_val]); } - PassMode::ByValPair(_, _) => { + PassMode::Pair(_, _) => { let place = fx.get_local_place(RETURN_PLACE); let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx); fx.bcx.ins().return_(&[ret_val_a, ret_val_b]); } + PassMode::Cast(cast) => { + let place = fx.get_local_place(RETURN_PLACE); + let ret_val = place.to_cvalue(fx); + let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast); + fx.bcx.ins().return_(&ret_vals); + } } } diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs index adf5c7ac4fee7..62fbcfe3f7a5d 100644 --- a/compiler/rustc_codegen_cranelift/src/analyze.rs +++ b/compiler/rustc_codegen_cranelift/src/analyze.rs @@ -40,11 +40,14 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, impl Module>) -> IndexVec { + TerminatorKind::Call { + destination, + func, + args, + .. + } => { if let Some((dest_place, _dest_bb)) = destination { - let dest_layout = fx - .layout_of(fx.monomorphize(&dest_place.ty(&fx.mir.local_decls, fx.tcx).ty)); - if !crate::abi::can_return_to_ssa_var(fx.tcx, dest_layout) { + if !crate::abi::can_return_to_ssa_var(fx, func, args) { not_ssa(&mut flag_map, dest_place.local) } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 34c9561d67622..4842628a99da7 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -2,6 +2,8 @@ use rustc_index::vec::IndexVec; use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::layout::FnAbiExt; +use rustc_target::abi::call::FnAbi; use crate::prelude::*; @@ -19,7 +21,8 @@ pub(crate) fn codegen_fn<'tcx>( let mir = tcx.instance_mir(instance.def); // Declare function - let (name, sig) = get_function_name_and_sig(tcx, cx.module.isa().triple(), instance, false); + let name = tcx.symbol_name(instance).name.to_string(); + let sig = get_function_sig(tcx, cx.module.isa().triple(), instance); let func_id = cx.module.declare_function(&name, linkage, &sig).unwrap(); cx.cached_context.clear(); @@ -50,6 +53,7 @@ pub(crate) fn codegen_fn<'tcx>( instance, mir, + fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])), bcx, block_map, @@ -117,6 +121,9 @@ pub(crate) fn codegen_fn<'tcx>( context.compute_domtree(); context.eliminate_unreachable_code(cx.module.isa()).unwrap(); context.dce(cx.module.isa()).unwrap(); + // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't + // invalidate it when it would change. + context.domtree.clear(); context.want_disasm = crate::pretty_clif::should_write_ir(tcx); @@ -1053,7 +1060,11 @@ pub(crate) fn codegen_panic_inner<'tcx>( fx.lib_call( &*symbol_name, - vec![fx.pointer_type, fx.pointer_type, fx.pointer_type], + vec![ + AbiParam::new(fx.pointer_type), + AbiParam::new(fx.pointer_type), + AbiParam::new(fx.pointer_type), + ], vec![], args, ); diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs index 58e45b4e9b972..be369b07fddfe 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs @@ -6,7 +6,7 @@ extern crate rustc_interface; extern crate rustc_session; extern crate rustc_target; -use rustc_data_structures::profiling::print_time_passes_entry; +use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_interface::interface; use rustc_session::config::ErrorOutputType; use rustc_session::early_error; @@ -39,7 +39,8 @@ impl rustc_driver::Callbacks for CraneliftPassesCallbacks { } fn main() { - let start = std::time::Instant::now(); + let start_time = std::time::Instant::now(); + let start_rss = get_resident_set_size(); rustc_driver::init_rustc_env_logger(); let mut callbacks = CraneliftPassesCallbacks::default(); rustc_driver::install_ice_hook(); @@ -61,7 +62,11 @@ fn main() { }))); run_compiler.run() }); - // The extra `\t` is necessary to align this label with the others. - print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed()); + + if callbacks.time_passes { + let end_rss = get_resident_set_size(); + print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss); + } + std::process::exit(exit_code) } diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs index 8ee4cd46c94e0..83e5dc6e6724d 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs @@ -53,10 +53,7 @@ impl rustc_driver::Callbacks for CraneliftPassesCallbacks { .unwrap() .parent() .unwrap() - .parent() - .unwrap() - .join("build_sysroot") - .join("sysroot"), + .to_owned(), ); } } diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs index d6a38bdafc9ba..866ba90e4ae4b 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs @@ -1,5 +1,7 @@ //! Replaces 128-bit operators with lang item calls where necessary +use cranelift_codegen::ir::ArgumentPurpose; + use crate::prelude::*; pub(crate) fn maybe_codegen<'tcx>( @@ -24,41 +26,41 @@ pub(crate) fn maybe_codegen<'tcx>( None } BinOp::Add | BinOp::Sub if !checked => None, - BinOp::Add => { - let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); - return Some(if is_signed { - fx.easy_call("__rust_i128_addo", &[lhs, rhs], out_ty) + BinOp::Mul if !checked => { + let val_ty = if is_signed { + fx.tcx.types.i128 } else { - fx.easy_call("__rust_u128_addo", &[lhs, rhs], out_ty) - }); + fx.tcx.types.u128 + }; + Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty)) } - BinOp::Sub => { + BinOp::Add | BinOp::Sub | BinOp::Mul => { + assert!(checked); let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); - return Some(if is_signed { - fx.easy_call("__rust_i128_subo", &[lhs, rhs], out_ty) - } else { - fx.easy_call("__rust_u128_subo", &[lhs, rhs], out_ty) - }); - } - BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), - BinOp::Mul => { - let res = if checked { - let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); - if is_signed { - fx.easy_call("__rust_i128_mulo", &[lhs, rhs], out_ty) - } else { - fx.easy_call("__rust_u128_mulo", &[lhs, rhs], out_ty) - } - } else { - let val_ty = if is_signed { - fx.tcx.types.i128 - } else { - fx.tcx.types.u128 - }; - fx.easy_call("__multi3", &[lhs, rhs], val_ty) + let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty)); + let param_types = vec![ + AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn), + AbiParam::new(types::I128), + AbiParam::new(types::I128), + ]; + let args = [ + out_place.to_ptr().get_addr(fx), + lhs.load_scalar(fx), + rhs.load_scalar(fx), + ]; + let name = match (bin_op, is_signed) { + (BinOp::Add, false) => "__rust_u128_addo", + (BinOp::Add, true) => "__rust_i128_addo", + (BinOp::Sub, false) => "__rust_u128_subo", + (BinOp::Sub, true) => "__rust_i128_subo", + (BinOp::Mul, false) => "__rust_u128_mulo", + (BinOp::Mul, true) => "__rust_i128_mulo", + _ => unreachable!(), }; - Some(res) + fx.lib_call(name, param_types, vec![], &args); + Some(out_place.to_cvalue(fx)) } + BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), BinOp::Div => { assert!(!checked); if is_signed { diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 1485d4451b815..fbee84e09f7a6 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -1,4 +1,5 @@ use rustc_index::vec::IndexVec; +use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Integer, Primitive}; use rustc_target::spec::{HasTargetSpec, Target}; @@ -294,6 +295,7 @@ pub(crate) struct FunctionCx<'clif, 'tcx, M: Module> { pub(crate) instance: Instance<'tcx>, pub(crate) mir: &'tcx Body<'tcx>, + pub(crate) fn_abi: Option>>, pub(crate) bcx: FunctionBuilder<'clif>, pub(crate) block_map: IndexVec, @@ -319,16 +321,7 @@ impl<'tcx, M: Module> LayoutOf for FunctionCx<'_, 'tcx, M> { type TyAndLayout = TyAndLayout<'tcx>; fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { - assert!(!ty.still_further_specializable()); - self.tcx - .layout_of(ParamEnv::reveal_all().and(&ty)) - .unwrap_or_else(|e| { - if let layout::LayoutError::SizeOverflow(_) = e { - self.tcx.sess.fatal(&e.to_string()) - } else { - bug!("failed to get layout for `{}`: {}", ty, e) - } - }) + RevealAllLayoutCx(self.tcx).layout_of(ty) } } @@ -442,3 +435,47 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { self.bcx.ins().global_value(self.pointer_type, local_msg_id) } } + +pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); + +impl<'tcx> LayoutOf for RevealAllLayoutCx<'tcx> { + type Ty = Ty<'tcx>; + type TyAndLayout = TyAndLayout<'tcx>; + + fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { + assert!(!ty.still_further_specializable()); + self.0 + .layout_of(ParamEnv::reveal_all().and(&ty)) + .unwrap_or_else(|e| { + if let layout::LayoutError::SizeOverflow(_) = e { + self.0.sess.fatal(&e.to_string()) + } else { + bug!("failed to get layout for `{}`: {}", ty, e) + } + }) + } +} + +impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.0 + } +} + +impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> { + fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout { + &self.0.data_layout + } +} + +impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + ParamEnv::reveal_all() + } +} + +impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> { + fn target_spec(&self) -> &Target { + &self.0.sess.target + } +} diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 16f9bfc99189f..df89883f0bbb7 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -281,9 +281,6 @@ pub(super) fn run_aot( None }; - rustc_incremental::assert_dep_graph(tcx); - rustc_incremental::save_dep_graph(tcx); - let metadata_module = if need_metadata_module { let _timer = tcx.prof.generic_activity("codegen crate metadata"); let (metadata_cgu_name, tmp_file) = tcx.sess.time("write compressed metadata", || { @@ -322,10 +319,6 @@ pub(super) fn run_aot( None }; - if tcx.sess.opts.output_types.should_codegen() { - rustc_incremental::assert_module_sources::assert_module_sources(tcx); - } - Box::new(( CodegenResults { crate_name: tcx.crate_name(LOCAL_CRATE), diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 9a42c675cc144..2d14ff2c0221d 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -156,12 +156,8 @@ extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 let jit_module = jit_module.as_mut().unwrap(); let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false); - let (name, sig) = crate::abi::get_function_name_and_sig( - tcx, - cx.module.isa().triple(), - instance, - true, - ); + let name = tcx.symbol_name(instance).name.to_string(); + let sig = crate::abi::get_function_sig(tcx, cx.module.isa().triple(), instance); let func_id = cx .module .declare_function(&name, Linkage::Export, &sig) @@ -246,8 +242,8 @@ pub(super) fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx, impl Module>, inst: In let pointer_type = cx.module.target_config().pointer_type(); - let (name, sig) = - crate::abi::get_function_name_and_sig(tcx, cx.module.isa().triple(), inst, true); + let name = tcx.symbol_name(inst).name.to_string(); + let sig = crate::abi::get_function_sig(tcx, cx.module.isa().triple(), inst); let func_id = cx .module .declare_function(&name, Linkage::Export, &sig) diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index 9f4ea9a386551..2497f9dfdfbcf 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -50,12 +50,9 @@ fn predefine_mono_items<'tcx>( for &(mono_item, (linkage, visibility)) in mono_items { match mono_item { MonoItem::Fn(instance) => { - let (name, sig) = get_function_name_and_sig( - cx.tcx, - cx.module.isa().triple(), - instance, - false, - ); + let name = cx.tcx.symbol_name(instance).name.to_string(); + let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name)); + let sig = get_function_sig(cx.tcx, cx.module.isa().triple(), instance); let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); cx.module.declare_function(&name, linkage, &sig).unwrap(); } diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index f31c58b92e407..170750461cace 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -27,7 +27,6 @@ extern crate rustc_incremental; extern crate rustc_index; extern crate rustc_session; extern crate rustc_span; -extern crate rustc_symbol_mangling; extern crate rustc_target; // This prevents duplicating functions and statics that are already part of the host rustc process. @@ -90,7 +89,8 @@ mod prelude { pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FloatTy, FnSig, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable, UintTy, + self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, + TypeFoldable, UintTy, }; pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx}; @@ -256,8 +256,6 @@ impl CodegenBackend for CraneliftCodegenBackend { }; let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config); - rustc_symbol_mangling::test::report_symbol_names(tcx); - res } @@ -279,18 +277,14 @@ impl CodegenBackend for CraneliftCodegenBackend { ) -> Result<(), ErrorReported> { use rustc_codegen_ssa::back::link::link_binary; - let _timer = sess.prof.generic_activity("link_crate"); - - sess.time("linking", || { - let target_cpu = crate::target_triple(sess).to_string(); - link_binary::>( - sess, - &codegen_results, - outputs, - &codegen_results.crate_name.as_str(), - &target_cpu, - ); - }); + let target_cpu = crate::target_triple(sess).to_string(); + link_binary::>( + sess, + &codegen_results, + outputs, + &codegen_results.crate_name.as_str(), + &target_cpu, + ); Ok(()) } @@ -345,7 +339,12 @@ fn build_isa(sess: &Session) -> Box { let flags = settings::Flags::new(flags_builder); - let mut isa_builder = cranelift_codegen::isa::lookup(target_triple).unwrap(); + let variant = if cfg!(feature = "oldbe") { + cranelift_codegen::isa::BackendVariant::Legacy + } else { + cranelift_codegen::isa::BackendVariant::MachInst + }; + let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt` // is interpreted as `bsr`. isa_builder.enable("nehalem").unwrap(); diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 6c472e6774fe7..b193cea877dad 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -69,8 +69,8 @@ pub(crate) fn maybe_create_entry_wrapper( let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx); - let (main_name, main_sig) = - get_function_name_and_sig(tcx, m.isa().triple(), instance, false); + let main_name = tcx.symbol_name(instance).name.to_string(); + let main_sig = get_function_sig(tcx, m.isa().triple(), instance); let main_func_id = m .declare_function(&main_name, Linkage::Import, &main_sig) .unwrap(); diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 41f4a9b9662bc..d1d2b3b872a4b 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -280,7 +280,6 @@ pub(crate) fn codegen_checked_int_binop<'tcx>( (val, fx.bcx.ins().bor(has_underflow, has_overflow)) } types::I64 => { - //let val = fx.easy_call("__mulodi4", &[lhs, rhs, overflow_ptr], types::I64); let val = fx.bcx.ins().imul(lhs, rhs); let has_overflow = if !signed { let val_hi = fx.bcx.ins().umulhi(lhs, rhs); diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index 22c94fec82fc1..f4a15ab12d511 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -61,7 +61,9 @@ use cranelift_codegen::{ write::{FuncWriter, PlainWriter}, }; +use rustc_middle::ty::layout::FnAbiExt; use rustc_session::config::OutputType; +use rustc_target::abi::call::FnAbi; use crate::prelude::*; @@ -78,11 +80,8 @@ impl CommentWriter { format!("symbol {}", tcx.symbol_name(instance).name), format!("instance {:?}", instance), format!( - "sig {:?}", - tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - crate::abi::fn_sig_for_fn_abi(tcx, instance) - ) + "abi {:?}", + FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[]) ), String::new(), ] diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 5bcb11fd515a0..765604e0f984e 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -334,7 +334,9 @@ impl<'tcx> CPlace<'tcx> { let stack_slot = fx.bcx.create_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, - size: u32::try_from(layout.size.bytes()).unwrap(), + // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to + // specify stack slot alignment. + size: (u32::try_from(layout.size.bytes()).unwrap() + 15) / 16 * 16, offset: None, }); CPlace { @@ -450,64 +452,6 @@ impl<'tcx> CPlace<'tcx> { fx: &mut FunctionCx<'_, 'tcx, impl Module>, from: CValue<'tcx>, ) { - fn assert_assignable<'tcx>( - fx: &FunctionCx<'_, 'tcx, impl Module>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, - ) { - match (from_ty.kind(), to_ty.kind()) { - (ty::Ref(_, a, _), ty::Ref(_, b, _)) - | ( - ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), - ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }), - ) => { - assert_assignable(fx, a, b); - } - (ty::FnPtr(_), ty::FnPtr(_)) => { - let from_sig = fx.tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - from_ty.fn_sig(fx.tcx), - ); - let to_sig = fx.tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - to_ty.fn_sig(fx.tcx), - ); - assert_eq!( - from_sig, to_sig, - "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}", - from_sig, to_sig, fx, - ); - // fn(&T) -> for<'l> fn(&'l T) is allowed - } - (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { - for (from, to) in from_traits.iter().zip(to_traits) { - let from = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); - let to = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); - assert_eq!( - from, to, - "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", - from_traits, to_traits, fx, - ); - } - // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed - } - _ => { - assert_eq!( - from_ty, - to_ty, - "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}", - from_ty, - to_ty, - fx, - ); - } - } - } - assert_assignable(fx, from.layout().ty, self.layout().ty); self.write_cvalue_maybe_transmute(fx, from, "write_cvalue"); @@ -556,7 +500,9 @@ impl<'tcx> CPlace<'tcx> { // FIXME do something more efficient for transmutes between vectors and integers. let stack_slot = fx.bcx.create_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, - size: src_ty.bytes(), + // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to + // specify stack slot alignment. + size: (src_ty.bytes() + 15) / 16 * 16, offset: None, }); let ptr = Pointer::stack_slot(stack_slot); @@ -794,3 +740,62 @@ impl<'tcx> CPlace<'tcx> { } } } + +#[track_caller] +pub(crate) fn assert_assignable<'tcx>( + fx: &FunctionCx<'_, 'tcx, impl Module>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) { + match (from_ty.kind(), to_ty.kind()) { + (ty::Ref(_, a, _), ty::Ref(_, b, _)) + | ( + ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), + ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }), + ) => { + assert_assignable(fx, a, b); + } + (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ })) + | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => { + assert_assignable(fx, a, b); + } + (ty::FnPtr(_), ty::FnPtr(_)) => { + let from_sig = fx.tcx.normalize_erasing_late_bound_regions( + ParamEnv::reveal_all(), + from_ty.fn_sig(fx.tcx), + ); + let to_sig = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_ty.fn_sig(fx.tcx)); + assert_eq!( + from_sig, to_sig, + "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}", + from_sig, to_sig, fx, + ); + // fn(&T) -> for<'l> fn(&'l T) is allowed + } + (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { + for (from, to) in from_traits.iter().zip(to_traits) { + let from = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); + let to = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); + assert_eq!( + from, to, + "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", + from_traits, to_traits, fx, + ); + } + // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed + } + _ => { + assert_eq!( + from_ty, to_ty, + "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}", + from_ty, to_ty, fx, + ); + } + } +} diff --git a/compiler/rustc_codegen_cranelift/test.sh b/compiler/rustc_codegen_cranelift/test.sh index c6c4956e48174..5ab10e0e905c7 100755 --- a/compiler/rustc_codegen_cranelift/test.sh +++ b/compiler/rustc_codegen_cranelift/test.sh @@ -1,9 +1,7 @@ #!/bin/bash set -e -export RUSTFLAGS="-Zrun_dsymutil=no" - -./build.sh --without-sysroot "$@" +./build.sh --sysroot none "$@" rm -r target/out || true diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 0ce85c5715f17..0fc11c286f899 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -12,7 +12,7 @@ use crate::{CachedModuleCodegen, CrateInfo, MemFlags, ModuleCodegen, ModuleKind} use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::profiling::print_time_passes_entry; +use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{par_iter, ParallelIterator}; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; @@ -595,6 +595,7 @@ pub fn codegen_crate( let mut cgu_reuse = Vec::new(); let mut pre_compiled_cgus: Option> = None; let mut total_codegen_time = Duration::new(0, 0); + let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size()); for (i, cgu) in codegen_units.iter().enumerate() { ongoing_codegen.wait_for_signal_to_codegen_item(); @@ -669,7 +670,16 @@ pub fn codegen_crate( // Since the main thread is sometimes blocked during codegen, we keep track // -Ztime-passes output manually. - print_time_passes_entry(tcx.sess.time_passes(), "codegen_to_LLVM_IR", total_codegen_time); + if tcx.sess.time_passes() { + let end_rss = get_resident_set_size(); + + print_time_passes_entry( + "codegen_to_LLVM_IR", + total_codegen_time, + start_rss.unwrap(), + end_rss, + ); + } ongoing_codegen.check_for_errors(tcx.sess); diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index b16d5a9e2b421..9a85b9d02c995 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -555,13 +555,16 @@ impl<'a> TimingGuard<'a> { #[must_use] pub struct VerboseTimingGuard<'a> { - start_and_message: Option<(Instant, String)>, + start_and_message: Option<(Instant, Option, String)>, _guard: TimingGuard<'a>, } impl<'a> VerboseTimingGuard<'a> { pub fn start(message: Option, _guard: TimingGuard<'a>) -> Self { - VerboseTimingGuard { _guard, start_and_message: message.map(|msg| (Instant::now(), msg)) } + VerboseTimingGuard { + _guard, + start_and_message: message.map(|msg| (Instant::now(), get_resident_set_size(), msg)), + } } #[inline(always)] @@ -573,25 +576,42 @@ impl<'a> VerboseTimingGuard<'a> { impl Drop for VerboseTimingGuard<'_> { fn drop(&mut self) { - if let Some((start, ref message)) = self.start_and_message { - print_time_passes_entry(true, &message[..], start.elapsed()); + if let Some((start_time, start_rss, ref message)) = self.start_and_message { + let end_rss = get_resident_set_size(); + print_time_passes_entry(&message[..], start_time.elapsed(), start_rss, end_rss); } } } -pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) { - if !do_it { - return; - } - - let mem_string = match get_resident() { - Some(n) => { - let mb = n as f64 / 1_000_000.0; - format!("; rss: {}MB", mb.round() as usize) +pub fn print_time_passes_entry( + what: &str, + dur: Duration, + start_rss: Option, + end_rss: Option, +) { + let rss_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as usize; + + let mem_string = match (start_rss, end_rss) { + (Some(start_rss), Some(end_rss)) => { + // It's tempting to add the change in RSS from start to end, but its somewhat confusing + // and misleading when looking at time-passes output. Consider two adjacent entries: + // + // time: 10.000; rss start: 1000MB, end: 1000MB, change: 0MB pass1 + // time: 5.000; rss start: 2000MB, end: 2000MB, change: 0MB pass2 + // + // If you're looking for jumps in RSS based on the change column, you miss the fact + // that a 1GB jump happened between pass1 and pass2 (supposing pass1 and pass2 actually + // occur sequentially and pass1 isn't just nested within pass2). It's easy to imagine + // someone missing this or being confused by the fact that the change is zero. + + format!("; rss: {:>5}MB -> {:>5}MB", rss_to_mb(start_rss), rss_to_mb(end_rss)) } - None => String::new(), + (Some(start_rss), None) => format!("; rss start: {:>5}MB", rss_to_mb(start_rss)), + (None, Some(end_rss)) => format!("; rss end: {:5>}MB", rss_to_mb(end_rss)), + (None, None) => String::new(), }; - println!("time: {}{}\t{}", duration_to_secs_str(dur), mem_string, what); + + println!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what); } // Hack up our own formatting for the duration to make it easier for scripts @@ -603,7 +623,7 @@ pub fn duration_to_secs_str(dur: std::time::Duration) -> String { // Memory reporting cfg_if! { if #[cfg(windows)] { - fn get_resident() -> Option { + pub fn get_resident_set_size() -> Option { use std::mem::{self, MaybeUninit}; use winapi::shared::minwindef::DWORD; use winapi::um::processthreadsapi::GetCurrentProcess; @@ -621,7 +641,7 @@ cfg_if! { } } } else if #[cfg(unix)] { - fn get_resident() -> Option { + pub fn get_resident_set_size() -> Option { let field = 1; let contents = fs::read("/proc/self/statm").ok()?; let contents = String::from_utf8(contents).ok()?; @@ -630,7 +650,7 @@ cfg_if! { Some(npages * 4096) } } else { - fn get_resident() -> Option { + pub fn get_resident_set_size() -> Option { None } } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 15b984acac590..8295e88f75ac7 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -16,7 +16,7 @@ pub extern crate rustc_plugin_impl as plugin; use rustc_ast as ast; use rustc_codegen_ssa::{traits::CodegenBackend, CodegenResults}; -use rustc_data_structures::profiling::print_time_passes_entry; +use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{ErrorReported, PResult}; @@ -1312,7 +1312,8 @@ pub fn init_env_logger(env: &str) { } pub fn main() -> ! { - let start = Instant::now(); + let start_time = Instant::now(); + let start_rss = get_resident_set_size(); init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); install_ice_hook(); @@ -1330,7 +1331,11 @@ pub fn main() -> ! { .collect::>(); RunCompiler::new(&args, &mut callbacks).run() }); - // The extra `\t` is necessary to align this label with the others. - print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed()); + + if callbacks.time_passes { + let end_rss = get_resident_set_size(); + print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss); + } + process::exit(exit_code) } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 4357eb34add23..1546c1e559f57 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -14,7 +14,7 @@ use crate::infer::canonical::{ }; use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::{InferCtxt, InferOk, InferResult, NLLRegionVariableOrigin}; +use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; use crate::traits::query::{Fallible, NoSolution}; use crate::traits::TraitEngine; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; @@ -644,7 +644,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { } fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { - let origin = NLLRegionVariableOrigin::Existential { from_forall }; + let origin = NllRegionVariableOrigin::Existential { from_forall }; self.infcx.next_nll_region_var(origin) } @@ -654,7 +654,7 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { self.infcx.next_nll_region_var_in_universe( - NLLRegionVariableOrigin::Existential { from_forall: false }, + NllRegionVariableOrigin::Existential { from_forall: false }, universe, ) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index c39daea0811e0..2abb1c725b914 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1661,6 +1661,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("exp_found {:?} terr {:?}", exp_found, terr); if let Some(exp_found) = exp_found { self.suggest_as_ref_where_appropriate(span, &exp_found, diag); + self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag); self.suggest_await_on_expect_found(cause, span, &exp_found, diag); } @@ -1819,6 +1820,53 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + fn suggest_accessing_field_where_appropriate( + &self, + cause: &ObligationCause<'tcx>, + exp_found: &ty::error::ExpectedFound>, + diag: &mut DiagnosticBuilder<'tcx>, + ) { + debug!( + "suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})", + cause, exp_found + ); + if let ty::Adt(expected_def, expected_substs) = exp_found.expected.kind() { + if expected_def.is_enum() { + return; + } + + if let Some((name, ty)) = expected_def + .non_enum_variant() + .fields + .iter() + .filter(|field| field.vis.is_accessible_from(field.did, self.tcx)) + .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs))) + .find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found)) + { + if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + let suggestion = if expected_def.is_struct() { + format!("{}.{}", snippet, name) + } else if expected_def.is_union() { + format!("unsafe {{ {}.{} }}", snippet, name) + } else { + return; + }; + diag.span_suggestion( + span, + &format!( + "you might have meant to use field `{}` of type `{}`", + name, ty + ), + suggestion, + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate, /// suggests it. fn suggest_as_ref_where_appropriate( @@ -2342,7 +2390,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); format!(" for capture of `{}` by closure", var_name) } - infer::NLL(..) => bug!("NLL variable found in lexical phase"), + infer::Nll(..) => bug!("NLL variable found in lexical phase"), }; struct_span_err!( diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 27545c126857b..09eecd715f03b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -458,11 +458,11 @@ pub enum RegionVariableOrigin { /// This origin is used for the inference variables that we create /// during NLL region processing. - NLL(NLLRegionVariableOrigin), + Nll(NllRegionVariableOrigin), } #[derive(Copy, Clone, Debug)] -pub enum NLLRegionVariableOrigin { +pub enum NllRegionVariableOrigin { /// During NLL region processing, we create variables for free /// regions that we encounter in the function signature and /// elsewhere. This origin indices we've got one of those. @@ -1078,17 +1078,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Just a convenient wrapper of `next_region_var` for using during NLL. - pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) -> ty::Region<'tcx> { - self.next_region_var(RegionVariableOrigin::NLL(origin)) + pub fn next_nll_region_var(&self, origin: NllRegionVariableOrigin) -> ty::Region<'tcx> { + self.next_region_var(RegionVariableOrigin::Nll(origin)) } /// Just a convenient wrapper of `next_region_var` for using during NLL. pub fn next_nll_region_var_in_universe( &self, - origin: NLLRegionVariableOrigin, + origin: NllRegionVariableOrigin, universe: ty::UniverseIndex, ) -> ty::Region<'tcx> { - self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe) + self.next_region_var_in_universe(RegionVariableOrigin::Nll(origin), universe) } pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg<'tcx> { @@ -1770,7 +1770,7 @@ impl RegionVariableOrigin { | LateBoundRegion(a, ..) | UpvarRegion(_, a) => a, BoundRegionInCoherence(_) => rustc_span::DUMMY_SP, - NLL(..) => bug!("NLL variable used with `span`"), + Nll(..) => bug!("NLL variable used with `span`"), } } } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index ebd6190dc74cc..121dde325f74b 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -56,8 +56,19 @@ declare_lint! { declare_lint_pass!(NonCamelCaseTypes => [NON_CAMEL_CASE_TYPES]); +/// Some unicode characters *have* case, are considered upper case or lower case, but they *can't* +/// be upper cased or lower cased. For the purposes of the lint suggestion, we care about being able +/// to change the char's case. fn char_has_case(c: char) -> bool { - c.is_lowercase() || c.is_uppercase() + let mut l = c.to_lowercase(); + let mut u = c.to_uppercase(); + while let Some(l) = l.next() { + match u.next() { + Some(u) if l != u => return true, + _ => {} + } + } + u.next().is_some() } fn is_camel_case(name: &str) -> bool { @@ -138,6 +149,8 @@ impl NonCamelCaseTypes { to_camel_case(name), Applicability::MaybeIncorrect, ); + } else { + err.span_label(ident.span, "should have an UpperCamelCase name"); } err.emit(); @@ -299,6 +312,8 @@ impl NonSnakeCase { } else { err.help(&format!("convert the identifier to snake case: `{}`", sc)); } + } else { + err.span_label(ident.span, "should have a snake_case name"); } err.emit(); @@ -477,6 +492,8 @@ impl NonUpperCaseGlobals { uc, Applicability::MaybeIncorrect, ); + } else { + err.span_label(ident.span, "should have an UPPER_CASE name"); } err.emit(); diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index a3d09c3a8d4c1..06e3f4b91f61f 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -5,7 +5,7 @@ use std::collections::VecDeque; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_index::vec::IndexVec; -use rustc_infer::infer::NLLRegionVariableOrigin; +use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, @@ -258,7 +258,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let (category, from_closure, span) = self.regioncx.best_blame_constraint( &self.body, borrow_region, - NLLRegionVariableOrigin::FreeRegion, + NllRegionVariableOrigin::FreeRegion, |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region), ); diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index ab83fc8dfaf75..058986593a41b 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -3,7 +3,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_infer::infer::{ error_reporting::nice_region_error::NiceRegionError, - error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin, + error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, }; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::subst::Subst; @@ -75,13 +75,13 @@ crate enum RegionErrorKind<'tcx> { /// The region element that erroneously must be outlived by `longer_fr`. error_element: RegionElement, /// The origin of the placeholder region. - fr_origin: NLLRegionVariableOrigin, + fr_origin: NllRegionVariableOrigin, }, /// Any other lifetime error. RegionError { /// The origin of the region. - fr_origin: NLLRegionVariableOrigin, + fr_origin: NllRegionVariableOrigin, /// The region that should outlive `shorter_fr`. longer_fr: RegionVid, /// The region that should be shorter, but we can't prove it. @@ -269,7 +269,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pub(in crate::borrow_check) fn report_region_error( &mut self, fr: RegionVid, - fr_origin: NLLRegionVariableOrigin, + fr_origin: NllRegionVariableOrigin, outlived_fr: RegionVid, outlives_suggestion: &mut OutlivesSuggestionBuilder, ) { diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs index d6e48deb031ac..86d9db294bf71 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs @@ -5,7 +5,7 @@ use super::{OutlivesConstraint, RegionInferenceContext}; use crate::borrow_check::type_check::Locations; -use rustc_infer::infer::NLLRegionVariableOrigin; +use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::ty::TyCtxt; use std::io::{self, Write}; @@ -20,7 +20,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { writeln!(out, "| Free Region Mapping")?; for region in self.regions() { - if let NLLRegionVariableOrigin::FreeRegion = self.definitions[region].origin { + if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin { let classification = self.universal_regions.region_classification(region).unwrap(); let outlived_by = self.universal_region_relations.regions_outlived_by(region); writeln!( diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs index 9d45f6fd0d348..bbd512fd36050 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_infer::infer::canonical::QueryOutlivesConstraint; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; -use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::mir::{ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint, @@ -143,9 +143,9 @@ pub(crate) struct AppliedMemberConstraint { pub(crate) struct RegionDefinition<'tcx> { /// What kind of variable is this -- a free region? existential - /// variable? etc. (See the `NLLRegionVariableOrigin` for more + /// variable? etc. (See the `NllRegionVariableOrigin` for more /// info.) - pub(in crate::borrow_check) origin: NLLRegionVariableOrigin, + pub(in crate::borrow_check) origin: NllRegionVariableOrigin, /// Which universe is this region variable defined in? This is /// most often `ty::UniverseIndex::ROOT`, but when we encounter @@ -451,7 +451,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let scc = self.constraint_sccs.scc(variable); match self.definitions[variable].origin { - NLLRegionVariableOrigin::FreeRegion => { + NllRegionVariableOrigin::FreeRegion => { // For each free, universally quantified region X: // Add all nodes in the CFG to liveness constraints @@ -462,7 +462,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.scc_values.add_element(scc, variable); } - NLLRegionVariableOrigin::Placeholder(placeholder) => { + NllRegionVariableOrigin::Placeholder(placeholder) => { // Each placeholder region is only visible from // its universe `ui` and its extensions. So we // can't just add it into `scc` unless the @@ -480,8 +480,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - NLLRegionVariableOrigin::RootEmptyRegion - | NLLRegionVariableOrigin::Existential { .. } => { + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::Existential { .. } => { // For existential, regions, nothing to do. } } @@ -1348,7 +1348,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) { for (fr, fr_definition) in self.definitions.iter_enumerated() { match fr_definition.origin { - NLLRegionVariableOrigin::FreeRegion => { + NllRegionVariableOrigin::FreeRegion => { // Go through each of the universal regions `fr` and check that // they did not grow too large, accumulating any requirements // for our caller into the `outlives_requirements` vector. @@ -1360,12 +1360,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { ); } - NLLRegionVariableOrigin::Placeholder(placeholder) => { + NllRegionVariableOrigin::Placeholder(placeholder) => { self.check_bound_universal_region(fr, placeholder, errors_buffer); } - NLLRegionVariableOrigin::RootEmptyRegion - | NLLRegionVariableOrigin::Existential { .. } => { + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::Existential { .. } => { // nothing to check here } } @@ -1449,7 +1449,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer.push(RegionErrorKind::RegionError { longer_fr: *longer_fr, shorter_fr: *shorter_fr, - fr_origin: NLLRegionVariableOrigin::FreeRegion, + fr_origin: NllRegionVariableOrigin::FreeRegion, is_reported: true, }); } @@ -1459,16 +1459,16 @@ impl<'tcx> RegionInferenceContext<'tcx> { // a more complete picture on how to separate this responsibility. for (fr, fr_definition) in self.definitions.iter_enumerated() { match fr_definition.origin { - NLLRegionVariableOrigin::FreeRegion => { + NllRegionVariableOrigin::FreeRegion => { // handled by polonius above } - NLLRegionVariableOrigin::Placeholder(placeholder) => { + NllRegionVariableOrigin::Placeholder(placeholder) => { self.check_bound_universal_region(fr, placeholder, errors_buffer); } - NLLRegionVariableOrigin::RootEmptyRegion - | NLLRegionVariableOrigin::Existential { .. } => { + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::Existential { .. } => { // nothing to check here } } @@ -1516,7 +1516,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer.push(RegionErrorKind::RegionError { longer_fr, shorter_fr: representative, - fr_origin: NLLRegionVariableOrigin::FreeRegion, + fr_origin: NllRegionVariableOrigin::FreeRegion, is_reported: true, }); } @@ -1539,7 +1539,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer.push(RegionErrorKind::RegionError { longer_fr, shorter_fr, - fr_origin: NLLRegionVariableOrigin::FreeRegion, + fr_origin: NllRegionVariableOrigin::FreeRegion, is_reported: !error_reported, }); @@ -1597,7 +1597,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let blame_span_category = self.find_outlives_blame_span( body, longer_fr, - NLLRegionVariableOrigin::FreeRegion, + NllRegionVariableOrigin::FreeRegion, shorter_fr, ); @@ -1656,7 +1656,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { longer_fr, error_element, - fr_origin: NLLRegionVariableOrigin::Placeholder(placeholder), + fr_origin: NllRegionVariableOrigin::Placeholder(placeholder), }); } @@ -1732,7 +1732,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2); match self.definitions[r2].origin { - NLLRegionVariableOrigin::Placeholder(placeholder) => { + NllRegionVariableOrigin::Placeholder(placeholder) => { let universe1 = self.definitions[r1].universe; debug!( "cannot_name_value_of: universe1={:?} placeholder={:?}", @@ -1741,9 +1741,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { universe1.cannot_name(placeholder.universe) } - NLLRegionVariableOrigin::RootEmptyRegion - | NLLRegionVariableOrigin::FreeRegion - | NLLRegionVariableOrigin::Existential { .. } => false, + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::FreeRegion + | NllRegionVariableOrigin::Existential { .. } => false, } } @@ -1771,7 +1771,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, body: &Body<'tcx>, fr1: RegionVid, - fr1_origin: NLLRegionVariableOrigin, + fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, ) -> (ConstraintCategory, Span) { let (category, _, span) = self.best_blame_constraint(body, fr1, fr1_origin, |r| { @@ -1933,7 +1933,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .definitions .iter_enumerated() .find_map(|(r, definition)| match definition.origin { - NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r), + NllRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r), _ => None, }) .unwrap(), @@ -1965,7 +1965,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, body: &Body<'tcx>, from_region: RegionVid, - from_region_origin: NLLRegionVariableOrigin, + from_region_origin: NllRegionVariableOrigin, target_test: impl Fn(RegionVid) -> bool, ) -> (ConstraintCategory, bool, Span) { debug!( @@ -2059,11 +2059,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { // // and here we prefer to blame the source (the y = x statement). let blame_source = match from_region_origin { - NLLRegionVariableOrigin::FreeRegion - | NLLRegionVariableOrigin::Existential { from_forall: false } => true, - NLLRegionVariableOrigin::RootEmptyRegion - | NLLRegionVariableOrigin::Placeholder(_) - | NLLRegionVariableOrigin::Existential { from_forall: true } => false, + NllRegionVariableOrigin::FreeRegion + | NllRegionVariableOrigin::Existential { from_forall: false } => true, + NllRegionVariableOrigin::RootEmptyRegion + | NllRegionVariableOrigin::Placeholder(_) + | NllRegionVariableOrigin::Existential { from_forall: true } => false, }; let find_region = |i: &usize| { @@ -2144,8 +2144,8 @@ impl<'tcx> RegionDefinition<'tcx> { // `init_universal_regions`. let origin = match rv_origin { - RegionVariableOrigin::NLL(origin) => origin, - _ => NLLRegionVariableOrigin::Existential { from_forall: false }, + RegionVariableOrigin::Nll(origin) => origin, + _ => NllRegionVariableOrigin::Existential { from_forall: false }, }; Self { origin, universe, external_name: None } diff --git a/compiler/rustc_mir/src/borrow_check/renumber.rs b/compiler/rustc_mir/src/borrow_check/renumber.rs index e563e37adc22b..9377473befe32 100644 --- a/compiler/rustc_mir/src/borrow_check/renumber.rs +++ b/compiler/rustc_mir/src/borrow_check/renumber.rs @@ -1,5 +1,5 @@ use rustc_index::vec::IndexVec; -use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::mir::visit::{MutVisitor, TyContext}; use rustc_middle::mir::{Body, Location, PlaceElem, Promoted}; use rustc_middle::ty::subst::SubstsRef; @@ -15,7 +15,7 @@ pub fn renumber_mir<'tcx>( debug!("renumber_mir()"); debug!("renumber_mir: body.arg_count={:?}", body.arg_count); - let mut visitor = NLLVisitor { infcx }; + let mut visitor = NllVisitor { infcx }; for body in promoted.iter_mut() { visitor.visit_body(body); @@ -33,16 +33,16 @@ where debug!("renumber_regions(value={:?})", value); infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { - let origin = NLLRegionVariableOrigin::Existential { from_forall: false }; + let origin = NllRegionVariableOrigin::Existential { from_forall: false }; infcx.next_nll_region_var(origin) }) } -struct NLLVisitor<'a, 'tcx> { +struct NllVisitor<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, } -impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { +impl<'a, 'tcx> NllVisitor<'a, 'tcx> { fn renumber_regions(&mut self, value: T) -> T where T: TypeFoldable<'tcx>, @@ -51,7 +51,7 @@ impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { } } -impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { +impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index e689964b99858..3ba06bdd6e05f 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ - InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin, + InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin, }; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; @@ -872,7 +872,7 @@ impl MirTypeckRegionConstraints<'tcx> { match self.placeholder_index_to_region.get(placeholder_index) { Some(&v) => v, None => { - let origin = NLLRegionVariableOrigin::Placeholder(placeholder); + let origin = NllRegionVariableOrigin::Placeholder(placeholder); let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe); self.placeholder_index_to_region.push(region); region diff --git a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs index 91b1a1fbd9705..6665eb5ad5fff 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs @@ -1,5 +1,5 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; -use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::{self, Const, Ty}; @@ -64,7 +64,7 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { if self.borrowck_context.is_some() { - let origin = NLLRegionVariableOrigin::Existential { from_forall }; + let origin = NllRegionVariableOrigin::Existential { from_forall }; self.infcx.next_nll_region_var(origin) } else { self.infcx.tcx.lifetimes.re_erased @@ -81,7 +81,7 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { self.infcx.next_nll_region_var_in_universe( - NLLRegionVariableOrigin::Existential { from_forall: false }, + NllRegionVariableOrigin::Existential { from_forall: false }, universe, ) } diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs index 02d951b70e28d..4b1acc1cd105e 100644 --- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -20,7 +20,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyOwnerKind, HirId}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; @@ -393,7 +393,7 @@ struct UniversalRegionsBuilder<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, } -const FR: NLLRegionVariableOrigin = NLLRegionVariableOrigin::FreeRegion; +const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion; impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { fn build(self) -> UniversalRegions<'tcx> { @@ -486,7 +486,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let root_empty = self .infcx - .next_nll_region_var(NLLRegionVariableOrigin::RootEmptyRegion) + .next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion) .to_region_vid(); UniversalRegions { @@ -647,7 +647,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { trait InferCtxtExt<'tcx> { fn replace_free_regions_with_nll_infer_vars( &self, - origin: NLLRegionVariableOrigin, + origin: NllRegionVariableOrigin, value: T, ) -> T where @@ -655,7 +655,7 @@ trait InferCtxtExt<'tcx> { fn replace_bound_regions_with_nll_infer_vars( &self, - origin: NLLRegionVariableOrigin, + origin: NllRegionVariableOrigin, all_outlive_scope: LocalDefId, value: ty::Binder, indices: &mut UniversalRegionIndices<'tcx>, @@ -673,7 +673,7 @@ trait InferCtxtExt<'tcx> { impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { fn replace_free_regions_with_nll_infer_vars( &self, - origin: NLLRegionVariableOrigin, + origin: NllRegionVariableOrigin, value: T, ) -> T where @@ -684,7 +684,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { fn replace_bound_regions_with_nll_infer_vars( &self, - origin: NLLRegionVariableOrigin, + origin: NllRegionVariableOrigin, all_outlive_scope: LocalDefId, value: ty::Binder, indices: &mut UniversalRegionIndices<'tcx>, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 2e108d480932a..90fcee075b5ac 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -82,8 +82,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// visible through borrow checking. False edges ensure that the CFG as /// seen by borrow checking doesn't encode this. False edges are added: /// - /// * From each prebinding block to the next prebinding block. - /// * From each otherwise block to the next prebinding block. + /// * From each pre-binding block to the next pre-binding block. + /// * From each otherwise block to the next pre-binding block. crate fn match_expr( &mut self, destination: Place<'tcx>, @@ -630,10 +630,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { #[derive(Debug)] pub(super) struct Candidate<'pat, 'tcx> { - /// `Span` of the original pattern that gave rise to this candidate + /// [`Span`] of the original pattern that gave rise to this candidate. span: Span, - /// This `Candidate` has a guard. + /// Whether this `Candidate` has a guard. has_guard: bool, /// All of these must be satisfied... @@ -645,14 +645,15 @@ pub(super) struct Candidate<'pat, 'tcx> { /// ...and these types asserted... ascriptions: Vec>, - /// ... and if this is non-empty, one of these subcandidates also has to match ... + /// ...and if this is non-empty, one of these subcandidates also has to match... subcandidates: Vec>, - /// ...and the guard must be evaluated, if false branch to Block... + /// ...and the guard must be evaluated; if it's `false` then branch to `otherwise_block`. otherwise_block: Option, - /// ...and the blocks for add false edges between candidates + /// The block before the `bindings` have been established. pre_binding_block: Option, + /// The pre-binding block of the next candidate. next_candidate_pre_binding_block: Option, } @@ -737,18 +738,19 @@ crate struct MatchPair<'pat, 'tcx> { pattern: &'pat Pat<'tcx>, } +/// See [`Test`] for more. #[derive(Clone, Debug, PartialEq)] enum TestKind<'tcx> { - /// Test the branches of enum. + /// Test what enum variant a value is. Switch { - /// The enum being tested + /// The enum type being tested. adt_def: &'tcx ty::AdtDef, /// The set of variants that we should create a branch for. We also /// create an additional "otherwise" case. variants: BitSet, }, - /// Test what value an `integer`, `bool` or `char` has. + /// Test what value an integer, `bool`, or `char` has. SwitchInt { /// The type of the value that we're testing. switch_ty: Ty<'tcx>, @@ -756,7 +758,7 @@ enum TestKind<'tcx> { /// /// For integers and `char`s we create a branch to each of the values in /// `options`, as well as an "otherwise" branch for all other values, even - /// in the (rare) case that options is exhaustive. + /// in the (rare) case that `options` is exhaustive. /// /// For `bool` we always generate two edges, one for `true` and one for /// `false`. @@ -776,17 +778,21 @@ enum TestKind<'tcx> { /// Test whether the value falls within an inclusive or exclusive range Range(PatRange<'tcx>), - /// Test length of the slice is equal to len + /// Test that the length of the slice is equal to `len`. Len { len: u64, op: BinOp }, } +/// A test to perform to determine which [`Candidate`] matches a value. +/// +/// [`Test`] is just the test to perform; it does not include the value +/// to be tested. #[derive(Debug)] crate struct Test<'tcx> { span: Span, kind: TestKind<'tcx>, } -/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether +/// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether /// a match arm has a guard expression attached to it. #[derive(Copy, Clone, Debug)] crate struct ArmHasGuard(crate bool); @@ -801,27 +807,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// candidates are sorted such that the first item in the list /// has the highest priority. When a candidate is found to match /// the value, we will set and generate a branch to the appropriate - /// prebinding block. + /// pre-binding block. /// /// If we find that *NONE* of the candidates apply, we branch to the /// `otherwise_block`, setting it to `Some` if required. In principle, this /// means that the input list was not exhaustive, though at present we /// sometimes are not smart enough to recognize all exhaustive inputs. /// - /// It might be surprising that the input can be inexhaustive. + /// It might be surprising that the input can be non-exhaustive. /// Indeed, initially, it is not, because all matches are /// exhaustive in Rust. But during processing we sometimes divide /// up the list of candidates and recurse with a non-exhaustive /// list. This is important to keep the size of the generated code - /// under control. See `test_candidates` for more details. + /// under control. See [`Builder::test_candidates`] for more details. /// - /// If `fake_borrows` is Some, then places which need fake borrows + /// If `fake_borrows` is `Some`, then places which need fake borrows /// will be added to it. /// /// For an example of a case where we set `otherwise_block`, even for an - /// exhaustive match consider: + /// exhaustive match, consider: /// - /// ```rust + /// ``` /// match x { /// (true, true) => (), /// (_, false) => (), @@ -830,8 +836,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// ``` /// /// For this match, we check if `x.0` matches `true` (for the first - /// arm). If that's false, we check `x.1`. If it's `true` we check if - /// `x.0` matches `false` (for the third arm). In the (impossible at + /// arm). If it doesn't match, we check `x.1`. If `x.1` is `true` we check + /// if `x.0` matches `false` (for the third arm). In the (impossible at /// runtime) case when `x.0` is now `true`, we branch to /// `otherwise_block`. fn match_candidates<'pat>( @@ -938,26 +944,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } - /// Link up matched candidates. For example, if we have something like - /// this: + /// Link up matched candidates. + /// + /// For example, if we have something like this: /// /// ```rust /// ... - /// Some(x) if cond => ... + /// Some(x) if cond1 => ... /// Some(x) => ... - /// Some(x) if cond => ... + /// Some(x) if cond2 => ... /// ... /// ``` /// /// We generate real edges from: - /// * `start_block` to the `prebinding_block` of the first pattern, - /// * the otherwise block of the first pattern to the second pattern, - /// * the otherwise block of the third pattern to the a block with an - /// Unreachable terminator. /// - /// As well as that we add fake edges from the otherwise blocks to the - /// prebinding block of the next candidate in the original set of + /// * `start_block` to the [pre-binding block] of the first pattern, + /// * the [otherwise block] of the first pattern to the second pattern, + /// * the [otherwise block] of the third pattern to a block with an + /// [`Unreachable` terminator](TerminatorKind::Unreachable). + /// + /// In addition, we add fake edges from the otherwise blocks to the + /// pre-binding block of the next candidate in the original set of /// candidates. + /// + /// [pre-binding block]: Candidate::pre_binding_block + /// [otherwise block]: Candidate::otherwise_block fn select_matched_candidates( &mut self, matched_candidates: &mut [&mut Candidate<'_, 'tcx>], @@ -1044,7 +1055,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// forwards to [Builder::test_candidates]. /// /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like - /// so + /// so: /// /// ```text /// [ start ] @@ -1214,10 +1225,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// This is the most subtle part of the matching algorithm. At /// this point, the input candidates have been fully simplified, /// and so we know that all remaining match-pairs require some - /// sort of test. To decide what test to do, we take the highest - /// priority candidate (last one in the list) and extract the - /// first match-pair from the list. From this we decide what kind - /// of test is needed using `test`, defined in the `test` module. + /// sort of test. To decide what test to perform, we take the highest + /// priority candidate (the first one in the list, as of January 2021) + /// and extract the first match-pair from the list. From this we decide + /// what kind of test is needed using [`Builder::test`], defined in the + /// [`test` module](mod@test). /// /// *Note:* taking the first match pair is somewhat arbitrary, and /// we might do better here by choosing more carefully what to @@ -1225,20 +1237,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// For example, consider the following possible match-pairs: /// - /// 1. `x @ Some(P)` -- we will do a `Switch` to decide what variant `x` has - /// 2. `x @ 22` -- we will do a `SwitchInt` - /// 3. `x @ 3..5` -- we will do a range test + /// 1. `x @ Some(P)` -- we will do a [`Switch`] to decide what variant `x` has + /// 2. `x @ 22` -- we will do a [`SwitchInt`] to decide what value `x` has + /// 3. `x @ 3..5` -- we will do a [`Range`] test to decide what range `x` falls in /// 4. etc. /// + /// [`Switch`]: TestKind::Switch + /// [`SwitchInt`]: TestKind::SwitchInt + /// [`Range`]: TestKind::Range + /// /// Once we know what sort of test we are going to perform, this - /// Tests may also help us with other candidates. So we walk over + /// test may also help us winnow down our candidates. So we walk over /// the candidates (from high to low priority) and check. This /// gives us, for each outcome of the test, a transformed list of - /// candidates. For example, if we are testing the current - /// variant of `x.0`, and we have a candidate `{x.0 @ Some(v), x.1 - /// @ 22}`, then we would have a resulting candidate of `{(x.0 as - /// Some).0 @ v, x.1 @ 22}`. Note that the first match-pair is now - /// simpler (and, in fact, irrefutable). + /// candidates. For example, if we are testing `x.0`'s variant, + /// and we have a candidate `(x.0 @ Some(v), x.1 @ 22)`, + /// then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)`. + /// Note that the first match-pair is now simpler (and, in fact, irrefutable). /// /// But there may also be candidates that the test just doesn't /// apply to. The classical example involves wildcards: @@ -1268,7 +1283,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// is trivially NP-complete: /// /// ```rust - /// match (var0, var1, var2, var3, ..) { + /// match (var0, var1, var2, var3, ...) { /// (true, _, _, false, true, ...) => false, /// (_, true, true, false, _, ...) => false, /// (false, _, false, false, _, ...) => false, @@ -1283,7 +1298,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// That kind of exponential worst-case might not occur in practice, but /// our simplistic treatment of constants and guards would make it occur - /// in very common situations - for example #29740: + /// in very common situations - for example [#29740]: /// /// ```rust /// match x { @@ -1294,13 +1309,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// } /// ``` /// - /// Here we first test the match-pair `x @ "foo"`, which is an `Eq` test. + /// [#29740]: https://github.com/rust-lang/rust/issues/29740 + /// + /// Here we first test the match-pair `x @ "foo"`, which is an [`Eq` test]. + /// + /// [`Eq` test]: TestKind::Eq /// /// It might seem that we would end up with 2 disjoint candidate - /// sets, consisting of the first candidate or the other 3, but our - /// algorithm doesn't reason about "foo" being distinct from the other + /// sets, consisting of the first candidate or the other two, but our + /// algorithm doesn't reason about `"foo"` being distinct from the other /// constants; it considers the latter arms to potentially match after - /// both outcomes, which obviously leads to an exponential amount + /// both outcomes, which obviously leads to an exponential number /// of tests. /// /// To avoid these kinds of problems, our algorithm tries to ensure @@ -1312,16 +1331,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// After we perform our test, we branch into the appropriate candidate /// set and recurse with `match_candidates`. These sub-matches are - /// obviously inexhaustive - as we discarded our otherwise set - so + /// obviously non-exhaustive - as we discarded our otherwise set - so /// we set their continuation to do `match_candidates` on the - /// "unmatched" set (which is again inexhaustive). + /// "unmatched" set (which is again non-exhaustive). /// /// If you apply this to the above test, you basically wind up /// with an if-else-if chain, testing each candidate in turn, /// which is precisely what we want. /// /// In addition to avoiding exponential-time blowups, this algorithm - /// also has nice property that each guard and arm is only generated + /// also has the nice property that each guard and arm is only generated /// once. fn test_candidates<'pat, 'b, 'c>( &mut self, diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 07173f41cd6db..126fb957a6a99 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -23,7 +23,7 @@ use std::cmp::Ordering; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. /// - /// It is a bug to call this with a simplifiable pattern. + /// It is a bug to call this with a not-fully-simplified pattern. pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { match *match_pair.pattern.kind { PatKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => Test { diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index ce83dc1de78c7..85e584d543507 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -13,4 +13,5 @@ rustc_typeck = { path = "../rustc_typeck" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_trait_selection = { path = "../rustc_trait_selection" } tracing = "0.1" diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 66206ca46c3a7..3fade2c443726 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -18,15 +18,17 @@ use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; +use rustc_middle::mir::abstract_const::Node as ACNode; use rustc_middle::span_bug; use rustc_middle::ty::fold::TypeVisitor; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{self, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::hygiene::Transparency; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst}; use std::marker::PhantomData; use std::ops::ControlFlow; @@ -112,19 +114,35 @@ where ty.visit_with(self) } ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE, - ty::PredicateKind::ConstEvaluatable(..) + ty::PredicateKind::ConstEvaluatable(defs, substs) if self.def_id_visitor.tcx().features().const_evaluatable_checked => { - // FIXME(const_evaluatable_checked): If the constant used here depends on a - // private function we may have to do something here... - // - // For now, let's just pretend that everything is fine. + let tcx = self.def_id_visitor.tcx(); + if let Ok(Some(ct)) = AbstractConst::new(tcx, defs, substs) { + self.visit_abstract_const_expr(tcx, ct)?; + } ControlFlow::CONTINUE } _ => bug!("unexpected predicate: {:?}", predicate), } } + fn visit_abstract_const_expr( + &mut self, + tcx: TyCtxt<'tcx>, + ct: AbstractConst<'tcx>, + ) -> ControlFlow { + const_evaluatable::walk_abstract_const(tcx, ct, |node| match node { + ACNode::Leaf(leaf) => { + let leaf = leaf.subst(tcx, ct.substs); + self.visit_const(leaf) + } + ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } + }) + } + fn visit_predicates( &mut self, predicates: ty::GenericPredicates<'tcx>, @@ -241,6 +259,15 @@ where ty.super_visit_with(self) } } + + fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow { + self.visit_ty(c.ty)?; + let tcx = self.def_id_visitor.tcx(); + if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) { + self.visit_abstract_const_expr(tcx, ct)?; + } + ControlFlow::CONTINUE + } } fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index dbc40a2eb9662..f7c0bafff05b4 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -6,7 +6,7 @@ pub mod auto_trait; mod chalk_fulfill; pub mod codegen; mod coherence; -mod const_evaluatable; +pub mod const_evaluatable; mod engine; pub mod error_reporting; mod fulfill; diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index fa7bd0d72d157..65bc2fcf00ae0 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -117,7 +117,7 @@ impl BufWriter { /// "successfully written" (by returning nonzero success values from /// `write`), any 0-length writes from `inner` must be reported as i/o /// errors from this method. - pub(super) fn flush_buf(&mut self) -> io::Result<()> { + pub(in crate::io) fn flush_buf(&mut self) -> io::Result<()> { /// Helper struct to ensure the buffer is updated after all the writes /// are complete. It tracks the number of written bytes and drains them /// all from the front of the buffer when dropped. @@ -243,6 +243,18 @@ impl BufWriter { &self.buf } + /// Returns a mutable reference to the internal buffer. + /// + /// This can be used to write data directly into the buffer without triggering writers + /// to the underlying writer. + /// + /// That the buffer is a `Vec` is an implementation detail. + /// Callers should not modify the capacity as there currently is no public API to do so + /// and thus any capacity changes would be unexpected by the user. + pub(in crate::io) fn buffer_mut(&mut self) -> &mut Vec { + &mut self.buf + } + /// Returns the number of bytes the internal buffer can hold without flushing. /// /// # Examples diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index b88bca2f2b4ff..3780f2044cb90 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,4 +1,4 @@ -use crate::io::{self, ErrorKind, Read, Write}; +use super::{BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}; use crate::mem::MaybeUninit; /// Copies the entire contents of a reader into a writer. @@ -40,7 +40,7 @@ use crate::mem::MaybeUninit; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub fn copy(reader: &mut R, writer: &mut W) -> io::Result +pub fn copy(reader: &mut R, writer: &mut W) -> Result where R: Read, W: Write, @@ -54,14 +54,82 @@ where } } -/// The general read-write-loop implementation of -/// `io::copy` that is used when specializations are not available or not applicable. -pub(crate) fn generic_copy(reader: &mut R, writer: &mut W) -> io::Result +/// The userspace read-write-loop implementation of `io::copy` that is used when +/// OS-specific specializations for copy offloading are not available or not applicable. +pub(crate) fn generic_copy(reader: &mut R, writer: &mut W) -> Result where R: Read, W: Write, { - let mut buf = MaybeUninit::<[u8; super::DEFAULT_BUF_SIZE]>::uninit(); + BufferedCopySpec::copy_to(reader, writer) +} + +/// Specialization of the read-write loop that either uses a stack buffer +/// or reuses the internal buffer of a BufWriter +trait BufferedCopySpec: Write { + fn copy_to(reader: &mut R, writer: &mut Self) -> Result; +} + +impl BufferedCopySpec for W { + default fn copy_to(reader: &mut R, writer: &mut Self) -> Result { + stack_buffer_copy(reader, writer) + } +} + +impl BufferedCopySpec for BufWriter { + fn copy_to(reader: &mut R, writer: &mut Self) -> Result { + if writer.capacity() < DEFAULT_BUF_SIZE { + return stack_buffer_copy(reader, writer); + } + + // FIXME: #42788 + // + // - This creates a (mut) reference to a slice of + // _uninitialized_ integers, which is **undefined behavior** + // + // - Only the standard library gets to soundly "ignore" this, + // based on its privileged knowledge of unstable rustc + // internals; + unsafe { + let spare_cap = writer.buffer_mut().spare_capacity_mut(); + reader.initializer().initialize(MaybeUninit::slice_assume_init_mut(spare_cap)); + } + + let mut len = 0; + + loop { + let buf = writer.buffer_mut(); + let spare_cap = buf.spare_capacity_mut(); + + if spare_cap.len() >= DEFAULT_BUF_SIZE { + match reader.read(unsafe { MaybeUninit::slice_assume_init_mut(spare_cap) }) { + Ok(0) => return Ok(len), // EOF reached + Ok(bytes_read) => { + assert!(bytes_read <= spare_cap.len()); + // Safety: The initializer contract guarantees that either it or `read` + // will have initialized these bytes. And we just checked that the number + // of bytes is within the buffer capacity. + unsafe { buf.set_len(buf.len() + bytes_read) }; + len += bytes_read as u64; + // Read again if the buffer still has enough capacity, as BufWriter itself would do + // This will occur if the reader returns short reads + continue; + } + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + } + } + + writer.flush_buf()?; + } + } +} + +fn stack_buffer_copy( + reader: &mut R, + writer: &mut W, +) -> Result { + let mut buf = MaybeUninit::<[u8; DEFAULT_BUF_SIZE]>::uninit(); // FIXME: #42788 // // - This creates a (mut) reference to a slice of diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs index df34e27d1361b..7632eaf872a5b 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/std/src/io/util/tests.rs @@ -1,5 +1,8 @@ +use crate::cmp::{max, min}; use crate::io::prelude::*; -use crate::io::{copy, empty, repeat, sink, Empty, Repeat, SeekFrom, Sink}; +use crate::io::{ + copy, empty, repeat, sink, BufWriter, Empty, Repeat, Result, SeekFrom, Sink, DEFAULT_BUF_SIZE, +}; #[test] fn copy_copies() { @@ -11,6 +14,51 @@ fn copy_copies() { assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); } +struct ShortReader { + cap: usize, + read_size: usize, + observed_buffer: usize, +} + +impl Read for ShortReader { + fn read(&mut self, buf: &mut [u8]) -> Result { + let bytes = min(self.cap, self.read_size); + self.cap -= bytes; + self.observed_buffer = max(self.observed_buffer, buf.len()); + Ok(bytes) + } +} + +struct WriteObserver { + observed_buffer: usize, +} + +impl Write for WriteObserver { + fn write(&mut self, buf: &[u8]) -> Result { + self.observed_buffer = max(self.observed_buffer, buf.len()); + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} + +#[test] +fn copy_specializes_bufwriter() { + let cap = 117 * 1024; + let buf_sz = 16 * 1024; + let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 }; + let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 }); + assert_eq!( + copy(&mut r, &mut w).unwrap(), + cap as u64, + "expected the whole capacity to be copied" + ); + assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader"); + assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes"); +} + #[test] fn sink_sinks() { let mut s = sink(); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 98bf7a9106aaa..b6929f5939576 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -284,6 +284,7 @@ #![feature(maybe_uninit_extra)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] +#![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] #![feature(needs_panic_runtime)] #![feature(negative_impls)] @@ -327,6 +328,7 @@ #![feature(unsafe_cell_raw_get)] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] +#![feature(vec_spare_capacity)] #![feature(wake_trait)] // NB: the above list is sorted to minimize merge conflicts. #![default_lib_allocator] diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index 017a4bbe97cc5..cbd3366b189ed 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -74,9 +74,9 @@ macro_rules! compat_fn { /// used, and would remove it. #[used] #[link_section = ".CRT$XCU"] - static INIT_TABLE_ENTRY: fn() = init; + static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; - fn init() { + unsafe extern "C" fn init() { // There is no locking here. This code is executed before main() is entered, and // is guaranteed to be single-threaded. // @@ -84,16 +84,14 @@ macro_rules! compat_fn { // any Rust functions or CRT functions, if those functions touch any global state, // because this function runs during global initialization. For example, DO NOT // do any dynamic allocation, don't call LoadLibrary, etc. - unsafe { - let module_name: *const u8 = concat!($module, "\0").as_ptr(); - let symbol_name: *const u8 = concat!(stringify!($symbol), "\0").as_ptr(); - let module_handle = $crate::sys::c::GetModuleHandleA(module_name as *const i8); - if !module_handle.is_null() { - match $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8) as usize { - 0 => {} - n => { - PTR = Some(mem::transmute::(n)); - } + let module_name: *const u8 = concat!($module, "\0").as_ptr(); + let symbol_name: *const u8 = concat!(stringify!($symbol), "\0").as_ptr(); + let module_handle = $crate::sys::c::GetModuleHandleA(module_name as *const i8); + if !module_handle.is_null() { + match $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8) as usize { + 0 => {} + n => { + PTR = Some(mem::transmute::(n)); } } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 39700c087a20d..34002019a6f1e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1050,8 +1050,10 @@ impl Step for Assemble { builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe)); } - // Similarly, copy `llvm-dwp` into libdir for Split DWARF. - { + // Similarly, copy `llvm-dwp` into libdir for Split DWARF. Only copy it when the LLVM + // backend is used to avoid unnecessarily building LLVM and because LLVM is not checked + // out by default when the LLVM backend is not enabled. + if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { let src_exe = exe("llvm-dwp", target_compiler.host); let dst_exe = exe("rust-llvm-dwp", target_compiler.host); let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host }); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 7e613220f2d69..4dbe7a37fcdc8 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1695,15 +1695,6 @@ function defocusSearchBar() { search.innerHTML = output; showSearchResults(search); - var tds = search.getElementsByTagName("td"); - var td_width = 0; - if (tds.length > 0) { - td_width = tds[0].offsetWidth; - } - var width = search.offsetWidth - 40 - td_width; - onEachLazy(search.getElementsByClassName("desc"), function(e) { - e.style.width = width + "px"; - }); initSearchNav(); var elems = document.getElementById("titles").childNodes; elems[0].onclick = function() { printTab(0); }; diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index cb16dc588d383..d50fda278bd7c 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1425,7 +1425,7 @@ h4 > .notable-traits { margin-left: 0px; } - #main { + #main, #search { margin-top: 45px; padding: 0; } @@ -1579,7 +1579,7 @@ h4 > .notable-traits { } } -@media (max-width: 416px) { +@media (max-width: 464px) { #titles, #titles > button { height: 73px; } diff --git a/src/test/ui/issues/issue-18425.rs b/src/test/ui/array-slice-vec/issue-18425.rs similarity index 100% rename from src/test/ui/issues/issue-18425.rs rename to src/test/ui/array-slice-vec/issue-18425.rs diff --git a/src/test/ui/issues/issue-18655.rs b/src/test/ui/associated-types/issue-18655.rs similarity index 100% rename from src/test/ui/issues/issue-18655.rs rename to src/test/ui/associated-types/issue-18655.rs diff --git a/src/test/ui/issues/issue-22037.rs b/src/test/ui/associated-types/issue-22037.rs similarity index 100% rename from src/test/ui/issues/issue-22037.rs rename to src/test/ui/associated-types/issue-22037.rs diff --git a/src/test/ui/issues/issue-22037.stderr b/src/test/ui/associated-types/issue-22037.stderr similarity index 100% rename from src/test/ui/issues/issue-22037.stderr rename to src/test/ui/associated-types/issue-22037.stderr diff --git a/src/test/ui/issues/issue-73541-2.rs b/src/test/ui/async-await/issue-73541-2.rs similarity index 100% rename from src/test/ui/issues/issue-73541-2.rs rename to src/test/ui/async-await/issue-73541-2.rs diff --git a/src/test/ui/issues/issue-73541-2.stderr b/src/test/ui/async-await/issue-73541-2.stderr similarity index 100% rename from src/test/ui/issues/issue-73541-2.stderr rename to src/test/ui/async-await/issue-73541-2.stderr diff --git a/src/test/ui/issues/issue-33819.rs b/src/test/ui/borrowck/issue-33819.rs similarity index 100% rename from src/test/ui/issues/issue-33819.rs rename to src/test/ui/borrowck/issue-33819.rs diff --git a/src/test/ui/issues/issue-33819.stderr b/src/test/ui/borrowck/issue-33819.stderr similarity index 100% rename from src/test/ui/issues/issue-33819.stderr rename to src/test/ui/borrowck/issue-33819.stderr diff --git a/src/test/ui/const-generics/const_evaluatable_checked/eval-privacy.rs b/src/test/ui/const-generics/const_evaluatable_checked/eval-privacy.rs new file mode 100644 index 0000000000000..9f457fbd346cd --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/eval-privacy.rs @@ -0,0 +1,31 @@ +#![crate_type = "lib"] +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +pub struct Const; + +pub trait Trait { + type AssocTy; + fn assoc_fn() -> Self::AssocTy; +} + +impl Trait for Const +//~^ WARN private type +//~| WARN this was previously +//~| WARN private type +//~| WARN this was previously + +where + Const<{ my_const_fn(U) }>: , +{ + type AssocTy = Const<{ my_const_fn(U) }>; + //~^ ERROR private type + fn assoc_fn() -> Self::AssocTy { + Const + } +} + +const fn my_const_fn(val: u8) -> u8 { + // body of this function doesn't matter + val +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/eval-privacy.stderr b/src/test/ui/const-generics/const_evaluatable_checked/eval-privacy.stderr new file mode 100644 index 0000000000000..842c22c5c6775 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/eval-privacy.stderr @@ -0,0 +1,43 @@ +warning: private type `fn(u8) -> u8 {my_const_fn}` in public interface (error E0446) + --> $DIR/eval-privacy.rs:12:1 + | +LL | / impl Trait for Const +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + | + = note: `#[warn(private_in_public)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #34537 + +warning: private type `fn(u8) -> u8 {my_const_fn}` in public interface (error E0446) + --> $DIR/eval-privacy.rs:12:1 + | +LL | / impl Trait for Const +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #34537 + +error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface + --> $DIR/eval-privacy.rs:21:5 + | +LL | type AssocTy = Const<{ my_const_fn(U) }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type +... +LL | const fn my_const_fn(val: u8) -> u8 { + | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private + +error: aborting due to previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0446`. diff --git a/src/test/ui/issues/issue-17458.rs b/src/test/ui/consts/issue-17458.rs similarity index 100% rename from src/test/ui/issues/issue-17458.rs rename to src/test/ui/consts/issue-17458.rs diff --git a/src/test/ui/issues/issue-17458.stderr b/src/test/ui/consts/issue-17458.stderr similarity index 100% rename from src/test/ui/issues/issue-17458.stderr rename to src/test/ui/consts/issue-17458.stderr diff --git a/src/test/ui/issues/issue-25826.rs b/src/test/ui/consts/issue-25826.rs similarity index 100% rename from src/test/ui/issues/issue-25826.rs rename to src/test/ui/consts/issue-25826.rs diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/consts/issue-25826.stderr similarity index 100% rename from src/test/ui/issues/issue-25826.stderr rename to src/test/ui/consts/issue-25826.stderr diff --git a/src/test/ui/issues/issue-46553.rs b/src/test/ui/consts/issue-46553.rs similarity index 100% rename from src/test/ui/issues/issue-46553.rs rename to src/test/ui/consts/issue-46553.rs diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/consts/issue-54348.rs similarity index 100% rename from src/test/ui/issues/issue-54348.rs rename to src/test/ui/consts/issue-54348.rs diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/consts/issue-54348.stderr similarity index 100% rename from src/test/ui/issues/issue-54348.stderr rename to src/test/ui/consts/issue-54348.stderr diff --git a/src/test/ui/issues/issue-56762.rs b/src/test/ui/consts/issue-56762.rs similarity index 100% rename from src/test/ui/issues/issue-56762.rs rename to src/test/ui/consts/issue-56762.rs diff --git a/src/test/ui/issues/issue-56762.stderr b/src/test/ui/consts/issue-56762.stderr similarity index 100% rename from src/test/ui/issues/issue-56762.stderr rename to src/test/ui/consts/issue-56762.stderr diff --git a/src/test/ui/issues/issue-10763.rs b/src/test/ui/extern/issue-10763.rs similarity index 100% rename from src/test/ui/issues/issue-10763.rs rename to src/test/ui/extern/issue-10763.rs diff --git a/src/test/ui/issues/issue-10764-rpass.rs b/src/test/ui/extern/issue-10764-rpass.rs similarity index 100% rename from src/test/ui/issues/issue-10764-rpass.rs rename to src/test/ui/extern/issue-10764-rpass.rs diff --git a/src/test/ui/issues/issue-2216.rs b/src/test/ui/for-loop-while/issue-2216.rs similarity index 100% rename from src/test/ui/issues/issue-2216.rs rename to src/test/ui/for-loop-while/issue-2216.rs diff --git a/src/test/ui/issues/issue-69841.rs b/src/test/ui/for-loop-while/issue-69841.rs similarity index 100% rename from src/test/ui/issues/issue-69841.rs rename to src/test/ui/for-loop-while/issue-69841.rs diff --git a/src/test/ui/issues/issue-14309.rs b/src/test/ui/lint/issue-14309.rs similarity index 100% rename from src/test/ui/issues/issue-14309.rs rename to src/test/ui/lint/issue-14309.rs diff --git a/src/test/ui/issues/issue-14309.stderr b/src/test/ui/lint/issue-14309.stderr similarity index 100% rename from src/test/ui/issues/issue-14309.stderr rename to src/test/ui/lint/issue-14309.stderr diff --git a/src/test/ui/lint/special-upper-lower-cases.stderr b/src/test/ui/lint/special-upper-lower-cases.stderr index f32193a2e4a47..e3b451a15a2cc 100644 --- a/src/test/ui/lint/special-upper-lower-cases.stderr +++ b/src/test/ui/lint/special-upper-lower-cases.stderr @@ -2,7 +2,7 @@ warning: type `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝` should have an upper camel --> $DIR/special-upper-lower-cases.rs:11:8 | LL | struct 𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝; - | ^^^^^^^^^ + | ^^^^^^^^^ should have an UpperCamelCase name | = note: `#[warn(non_camel_case_types)]` on by default @@ -10,13 +10,13 @@ warning: type `𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝` should have an upper came --> $DIR/special-upper-lower-cases.rs:15:8 | LL | struct 𝕟𝕠𝕥_𝕒_𝕔𝕒𝕞𝕖𝕝; - | ^^^^^^^^^^^ help: convert the identifier to upper camel case: `𝕟𝕠𝕥𝕒𝕔𝕒𝕞𝕖𝕝` + | ^^^^^^^^^^^ should have an UpperCamelCase name warning: static variable `𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲` should have an upper case name --> $DIR/special-upper-lower-cases.rs:18:8 | LL | static 𝗻𝗼𝗻𝘂𝗽𝗽𝗲𝗿𝗰𝗮𝘀𝗲: i32 = 1; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ should have an UPPER_CASE name | = note: `#[warn(non_upper_case_globals)]` on by default @@ -24,7 +24,7 @@ warning: variable `𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢` should have a snake cas --> $DIR/special-upper-lower-cases.rs:22:9 | LL | let 𝓢𝓝𝓐𝓐𝓐𝓐𝓚𝓔𝓢 = 1; - | ^^^^^^^^^ + | ^^^^^^^^^ should have a snake_case name | = note: `#[warn(non_snake_case)]` on by default diff --git a/src/test/ui/issues/issue-33264.rs b/src/test/ui/llvm-asm/issue-33264.rs similarity index 100% rename from src/test/ui/issues/issue-33264.rs rename to src/test/ui/llvm-asm/issue-33264.rs diff --git a/src/test/ui/issues/issue-8709.rs b/src/test/ui/macros/issue-8709.rs similarity index 100% rename from src/test/ui/issues/issue-8709.rs rename to src/test/ui/macros/issue-8709.rs diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.rs b/src/test/ui/nll/issue-45696-scribble-on-boxed-borrow.rs similarity index 100% rename from src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.rs rename to src/test/ui/nll/issue-45696-scribble-on-boxed-borrow.rs diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.stderr b/src/test/ui/nll/issue-45696-scribble-on-boxed-borrow.stderr similarity index 100% rename from src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.stderr rename to src/test/ui/nll/issue-45696-scribble-on-boxed-borrow.stderr diff --git a/src/test/ui/issues/issue-46036.rs b/src/test/ui/nll/issue-46036.rs similarity index 100% rename from src/test/ui/issues/issue-46036.rs rename to src/test/ui/nll/issue-46036.rs diff --git a/src/test/ui/issues/issue-46036.stderr b/src/test/ui/nll/issue-46036.stderr similarity index 100% rename from src/test/ui/issues/issue-46036.stderr rename to src/test/ui/nll/issue-46036.stderr diff --git a/src/test/ui/issues/issue-20616-8.rs b/src/test/ui/parser/issue-20616-8.rs similarity index 100% rename from src/test/ui/issues/issue-20616-8.rs rename to src/test/ui/parser/issue-20616-8.rs diff --git a/src/test/ui/issues/issue-20616-8.stderr b/src/test/ui/parser/issue-20616-8.stderr similarity index 100% rename from src/test/ui/issues/issue-20616-8.stderr rename to src/test/ui/parser/issue-20616-8.stderr diff --git a/src/test/ui/issues/issue-20616-9.rs b/src/test/ui/parser/issue-20616-9.rs similarity index 100% rename from src/test/ui/issues/issue-20616-9.rs rename to src/test/ui/parser/issue-20616-9.rs diff --git a/src/test/ui/issues/issue-20616-9.stderr b/src/test/ui/parser/issue-20616-9.stderr similarity index 100% rename from src/test/ui/issues/issue-20616-9.stderr rename to src/test/ui/parser/issue-20616-9.stderr diff --git a/src/test/ui/issues/issue-57198.rs b/src/test/ui/parser/issue-57198.rs similarity index 100% rename from src/test/ui/issues/issue-57198.rs rename to src/test/ui/parser/issue-57198.rs diff --git a/src/test/ui/issues/issue-57198.stderr b/src/test/ui/parser/issue-57198.stderr similarity index 100% rename from src/test/ui/issues/issue-57198.stderr rename to src/test/ui/parser/issue-57198.stderr diff --git a/src/test/ui/issues/issue-57684.fixed b/src/test/ui/parser/issue-57684.fixed similarity index 100% rename from src/test/ui/issues/issue-57684.fixed rename to src/test/ui/parser/issue-57684.fixed diff --git a/src/test/ui/issues/issue-57684.rs b/src/test/ui/parser/issue-57684.rs similarity index 100% rename from src/test/ui/issues/issue-57684.rs rename to src/test/ui/parser/issue-57684.rs diff --git a/src/test/ui/issues/issue-57684.stderr b/src/test/ui/parser/issue-57684.stderr similarity index 100% rename from src/test/ui/issues/issue-57684.stderr rename to src/test/ui/parser/issue-57684.stderr diff --git a/src/test/ui/issues/issue-57819.fixed b/src/test/ui/parser/issue-57819.fixed similarity index 100% rename from src/test/ui/issues/issue-57819.fixed rename to src/test/ui/parser/issue-57819.fixed diff --git a/src/test/ui/issues/issue-57819.rs b/src/test/ui/parser/issue-57819.rs similarity index 100% rename from src/test/ui/issues/issue-57819.rs rename to src/test/ui/parser/issue-57819.rs diff --git a/src/test/ui/issues/issue-57819.stderr b/src/test/ui/parser/issue-57819.stderr similarity index 100% rename from src/test/ui/issues/issue-57819.stderr rename to src/test/ui/parser/issue-57819.stderr diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/parser/issue-58856-1.rs similarity index 100% rename from src/test/ui/issues/issue-58856-1.rs rename to src/test/ui/parser/issue-58856-1.rs diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/parser/issue-58856-1.stderr similarity index 100% rename from src/test/ui/issues/issue-58856-1.stderr rename to src/test/ui/parser/issue-58856-1.stderr diff --git a/src/test/ui/issues/issue-64732.rs b/src/test/ui/parser/issue-64732.rs similarity index 100% rename from src/test/ui/issues/issue-64732.rs rename to src/test/ui/parser/issue-64732.rs diff --git a/src/test/ui/issues/issue-64732.stderr b/src/test/ui/parser/issue-64732.stderr similarity index 100% rename from src/test/ui/issues/issue-64732.stderr rename to src/test/ui/parser/issue-64732.stderr diff --git a/src/test/ui/issues/issue-7970b.rs b/src/test/ui/parser/issue-7970b.rs similarity index 100% rename from src/test/ui/issues/issue-7970b.rs rename to src/test/ui/parser/issue-7970b.rs diff --git a/src/test/ui/issues/issue-7970b.stderr b/src/test/ui/parser/issue-7970b.stderr similarity index 100% rename from src/test/ui/issues/issue-7970b.stderr rename to src/test/ui/parser/issue-7970b.stderr diff --git a/src/test/ui/issues/issue-50599.rs b/src/test/ui/resolve/issue-50599.rs similarity index 100% rename from src/test/ui/issues/issue-50599.rs rename to src/test/ui/resolve/issue-50599.rs diff --git a/src/test/ui/issues/issue-50599.stderr b/src/test/ui/resolve/issue-50599.stderr similarity index 100% rename from src/test/ui/issues/issue-50599.stderr rename to src/test/ui/resolve/issue-50599.stderr diff --git a/src/test/ui/issues/issue-32947.rs b/src/test/ui/simd/issue-32947.rs similarity index 100% rename from src/test/ui/issues/issue-32947.rs rename to src/test/ui/simd/issue-32947.rs diff --git a/src/test/ui/suggestions/field-access.fixed b/src/test/ui/suggestions/field-access.fixed new file mode 100644 index 0000000000000..05a4a0eb1266d --- /dev/null +++ b/src/test/ui/suggestions/field-access.fixed @@ -0,0 +1,35 @@ +// run-rustfix +#![allow(dead_code)] + +struct A { + b: B, +} + +enum B { + Fst, + Snd, +} + +union Foo { + bar: u32, + qux: f32, +} + +fn main() { + let a = A { b: B::Fst }; + if let B::Fst = a.b {}; //~ ERROR mismatched types [E0308] + //~^ HELP you might have meant to use field `b` of type `B` + match a.b { + //~^ HELP you might have meant to use field `b` of type `B` + //~| HELP you might have meant to use field `b` of type `B` + B::Fst => (), //~ ERROR mismatched types [E0308] + B::Snd => (), //~ ERROR mismatched types [E0308] + } + + let foo = Foo { bar: 42 }; + match unsafe { foo.bar } { + //~^ HELP you might have meant to use field `bar` of type `u32` + 1u32 => (), //~ ERROR mismatched types [E0308] + _ => (), + } +} diff --git a/src/test/ui/suggestions/field-access.rs b/src/test/ui/suggestions/field-access.rs new file mode 100644 index 0000000000000..ad23c0ffa2e74 --- /dev/null +++ b/src/test/ui/suggestions/field-access.rs @@ -0,0 +1,35 @@ +// run-rustfix +#![allow(dead_code)] + +struct A { + b: B, +} + +enum B { + Fst, + Snd, +} + +union Foo { + bar: u32, + qux: f32, +} + +fn main() { + let a = A { b: B::Fst }; + if let B::Fst = a {}; //~ ERROR mismatched types [E0308] + //~^ HELP you might have meant to use field `b` of type `B` + match a { + //~^ HELP you might have meant to use field `b` of type `B` + //~| HELP you might have meant to use field `b` of type `B` + B::Fst => (), //~ ERROR mismatched types [E0308] + B::Snd => (), //~ ERROR mismatched types [E0308] + } + + let foo = Foo { bar: 42 }; + match foo { + //~^ HELP you might have meant to use field `bar` of type `u32` + 1u32 => (), //~ ERROR mismatched types [E0308] + _ => (), + } +} diff --git a/src/test/ui/suggestions/field-access.stderr b/src/test/ui/suggestions/field-access.stderr new file mode 100644 index 0000000000000..aad9872032a2a --- /dev/null +++ b/src/test/ui/suggestions/field-access.stderr @@ -0,0 +1,67 @@ +error[E0308]: mismatched types + --> $DIR/field-access.rs:20:12 + | +LL | Fst, + | --- unit variant defined here +... +LL | if let B::Fst = a {}; + | ^^^^^^ - this expression has type `A` + | | + | expected struct `A`, found enum `B` + | +help: you might have meant to use field `b` of type `B` + | +LL | if let B::Fst = a.b {}; + | ^^^ + +error[E0308]: mismatched types + --> $DIR/field-access.rs:25:9 + | +LL | Fst, + | --- unit variant defined here +... +LL | match a { + | - this expression has type `A` +... +LL | B::Fst => (), + | ^^^^^^ expected struct `A`, found enum `B` + | +help: you might have meant to use field `b` of type `B` + | +LL | match a.b { + | ^^^ + +error[E0308]: mismatched types + --> $DIR/field-access.rs:26:9 + | +LL | Snd, + | --- unit variant defined here +... +LL | match a { + | - this expression has type `A` +... +LL | B::Snd => (), + | ^^^^^^ expected struct `A`, found enum `B` + | +help: you might have meant to use field `b` of type `B` + | +LL | match a.b { + | ^^^ + +error[E0308]: mismatched types + --> $DIR/field-access.rs:32:9 + | +LL | match foo { + | --- this expression has type `Foo` +LL | +LL | 1u32 => (), + | ^^^^ expected union `Foo`, found `u32` + | +help: you might have meant to use field `bar` of type `u32` + | +LL | match unsafe { foo.bar } { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-53675-a-test-called-panic.rs b/src/test/ui/test-attrs/issue-53675-a-test-called-panic.rs similarity index 100% rename from src/test/ui/issues/issue-53675-a-test-called-panic.rs rename to src/test/ui/test-attrs/issue-53675-a-test-called-panic.rs diff --git a/src/test/ui/issues/issue-4446.rs b/src/test/ui/threads-sendsync/issue-4446.rs similarity index 100% rename from src/test/ui/issues/issue-4446.rs rename to src/test/ui/threads-sendsync/issue-4446.rs diff --git a/src/test/ui/issues/issue-33140-hack-boundaries.rs b/src/test/ui/traits/issue-33140-hack-boundaries.rs similarity index 100% rename from src/test/ui/issues/issue-33140-hack-boundaries.rs rename to src/test/ui/traits/issue-33140-hack-boundaries.rs diff --git a/src/test/ui/issues/issue-33140-hack-boundaries.stderr b/src/test/ui/traits/issue-33140-hack-boundaries.stderr similarity index 100% rename from src/test/ui/issues/issue-33140-hack-boundaries.stderr rename to src/test/ui/traits/issue-33140-hack-boundaries.stderr diff --git a/src/test/ui/issues/issue-3683.rs b/src/test/ui/traits/issue-3683.rs similarity index 100% rename from src/test/ui/issues/issue-3683.rs rename to src/test/ui/traits/issue-3683.rs diff --git a/src/test/ui/issues/issue-56202.rs b/src/test/ui/traits/issue-56202.rs similarity index 100% rename from src/test/ui/issues/issue-56202.rs rename to src/test/ui/traits/issue-56202.rs diff --git a/src/test/ui/issues/issue-56488.rs b/src/test/ui/traits/issue-56488.rs similarity index 100% rename from src/test/ui/issues/issue-56488.rs rename to src/test/ui/traits/issue-56488.rs diff --git a/src/test/ui/issues/issue-59029-2.rs b/src/test/ui/traits/issue-59029-2.rs similarity index 100% rename from src/test/ui/issues/issue-59029-2.rs rename to src/test/ui/traits/issue-59029-2.rs diff --git a/src/test/ui/issues/issue-6128.rs b/src/test/ui/traits/issue-6128.rs similarity index 100% rename from src/test/ui/issues/issue-6128.rs rename to src/test/ui/traits/issue-6128.rs diff --git a/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs b/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.rs similarity index 100% rename from src/test/ui/issues/issue-65284-suggest-generic-trait-bound.rs rename to src/test/ui/traits/issue-65284-suggest-generic-trait-bound.rs diff --git a/src/test/ui/issues/issue-65284-suggest-generic-trait-bound.stderr b/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr similarity index 100% rename from src/test/ui/issues/issue-65284-suggest-generic-trait-bound.stderr rename to src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 21d05226fb42c..74ed236675208 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -8,7 +8,7 @@ use std::path::Path; const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. const ROOT_ENTRY_LIMIT: usize = 1459; -const ISSUES_ENTRY_LIMIT: usize = 2669; +const ISSUES_ENTRY_LIMIT: usize = 2615; fn check_entries(path: &Path, bad: &mut bool) { let dirs = walkdir::WalkDir::new(&path.join("test/ui"))